xref: /llvm-project/clang/unittests/Analysis/CFGDominatorTree.cpp (revision c79345fb7b149d9c952f8506c9e6c6317a5b4cd8)
12e2db937SKristof Umann //===- unittests/Analysis/CFGDominatorTree.cpp - CFG tests ----------------===//
22e2db937SKristof Umann //
32e2db937SKristof Umann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42e2db937SKristof Umann // See https://llvm.org/LICENSE.txt for license information.
52e2db937SKristof Umann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62e2db937SKristof Umann //
72e2db937SKristof Umann //===----------------------------------------------------------------------===//
82e2db937SKristof Umann 
92e2db937SKristof Umann #include "CFGBuildResult.h"
102e2db937SKristof Umann #include "clang/Analysis/Analyses/Dominators.h"
112e2db937SKristof Umann #include "gtest/gtest.h"
122e2db937SKristof Umann 
132e2db937SKristof Umann namespace clang {
142e2db937SKristof Umann namespace analysis {
152e2db937SKristof Umann namespace {
162e2db937SKristof Umann 
TEST(CFGDominatorTree,DomTree)172e2db937SKristof Umann TEST(CFGDominatorTree, DomTree) {
182e2db937SKristof Umann   const char *Code = R"(enum Kind {
192e2db937SKristof Umann                           A
202e2db937SKristof Umann                         };
212e2db937SKristof Umann 
222e2db937SKristof Umann                         void f() {
232e2db937SKristof Umann                           switch(Kind{}) {
242e2db937SKristof Umann                           case A:
252e2db937SKristof Umann                             break;
262e2db937SKristof Umann                           }
272e2db937SKristof Umann                         })";
282e2db937SKristof Umann   BuildResult Result = BuildCFG(Code);
292e2db937SKristof Umann   EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
302e2db937SKristof Umann 
312e2db937SKristof Umann   //  [B3 (ENTRY)]  -> [B1] -> [B2] -> [B0 (EXIT)]
322e2db937SKristof Umann   //                  switch  case A
332e2db937SKristof Umann 
342e2db937SKristof Umann   CFG *cfg = Result.getCFG();
352e2db937SKristof Umann 
36*c79345fbSZarko Todorovski   // Basic correctness checks.
372e2db937SKristof Umann   EXPECT_EQ(cfg->size(), 4u);
382e2db937SKristof Umann 
392e2db937SKristof Umann   CFGBlock *ExitBlock = *cfg->begin();
402e2db937SKristof Umann   EXPECT_EQ(ExitBlock, &cfg->getExit());
412e2db937SKristof Umann 
422e2db937SKristof Umann   CFGBlock *SwitchBlock = *(cfg->begin() + 1);
432e2db937SKristof Umann 
442e2db937SKristof Umann   CFGBlock *CaseABlock = *(cfg->begin() + 2);
452e2db937SKristof Umann 
462e2db937SKristof Umann   CFGBlock *EntryBlock = *(cfg->begin() + 3);
472e2db937SKristof Umann   EXPECT_EQ(EntryBlock, &cfg->getEntry());
482e2db937SKristof Umann 
492e2db937SKristof Umann   // Test the dominator tree.
502e2db937SKristof Umann   CFGDomTree Dom;
512e2db937SKristof Umann   Dom.buildDominatorTree(cfg);
522e2db937SKristof Umann 
532e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(ExitBlock, ExitBlock));
542e2db937SKristof Umann   EXPECT_FALSE(Dom.properlyDominates(ExitBlock, ExitBlock));
552e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(CaseABlock, ExitBlock));
562e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(SwitchBlock, ExitBlock));
572e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(EntryBlock, ExitBlock));
582e2db937SKristof Umann 
592e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(CaseABlock, CaseABlock));
602e2db937SKristof Umann   EXPECT_FALSE(Dom.properlyDominates(CaseABlock, CaseABlock));
612e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(SwitchBlock, CaseABlock));
622e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(EntryBlock, CaseABlock));
632e2db937SKristof Umann 
642e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(SwitchBlock, SwitchBlock));
652e2db937SKristof Umann   EXPECT_FALSE(Dom.properlyDominates(SwitchBlock, SwitchBlock));
662e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(EntryBlock, SwitchBlock));
672e2db937SKristof Umann 
682e2db937SKristof Umann   EXPECT_TRUE(Dom.dominates(EntryBlock, EntryBlock));
692e2db937SKristof Umann   EXPECT_FALSE(Dom.properlyDominates(EntryBlock, EntryBlock));
702e2db937SKristof Umann 
712e2db937SKristof Umann   // Test the post dominator tree.
722e2db937SKristof Umann 
732e2db937SKristof Umann   CFGPostDomTree PostDom;
742e2db937SKristof Umann   PostDom.buildDominatorTree(cfg);
752e2db937SKristof Umann 
762e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(ExitBlock, EntryBlock));
772e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(CaseABlock, EntryBlock));
782e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(SwitchBlock, EntryBlock));
792e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(EntryBlock, EntryBlock));
802e2db937SKristof Umann   EXPECT_FALSE(Dom.properlyDominates(EntryBlock, EntryBlock));
812e2db937SKristof Umann 
822e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(ExitBlock, SwitchBlock));
832e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(CaseABlock, SwitchBlock));
842e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(SwitchBlock, SwitchBlock));
852e2db937SKristof Umann   EXPECT_FALSE(Dom.properlyDominates(SwitchBlock, SwitchBlock));
862e2db937SKristof Umann 
872e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(ExitBlock, CaseABlock));
882e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(CaseABlock, CaseABlock));
892e2db937SKristof Umann   EXPECT_FALSE(Dom.properlyDominates(CaseABlock, CaseABlock));
902e2db937SKristof Umann 
912e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(ExitBlock, ExitBlock));
922e2db937SKristof Umann   EXPECT_FALSE(Dom.properlyDominates(ExitBlock, ExitBlock));
932e2db937SKristof Umann 
942e2db937SKristof Umann   // Tests for the post dominator tree's virtual root.
952e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(nullptr, EntryBlock));
962e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(nullptr, SwitchBlock));
972e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(nullptr, CaseABlock));
982e2db937SKristof Umann   EXPECT_TRUE(PostDom.dominates(nullptr, ExitBlock));
992e2db937SKristof Umann }
1002e2db937SKristof Umann 
TEST(CFGDominatorTree,ControlDependency)1015e17ee1eSKristof Umann TEST(CFGDominatorTree, ControlDependency) {
1025e17ee1eSKristof Umann   const char *Code = R"(bool coin();
1035e17ee1eSKristof Umann 
1045e17ee1eSKristof Umann                         void funcWithBranch() {
1055e17ee1eSKristof Umann                           int x = 0;
1065e17ee1eSKristof Umann                           if (coin()) {
1075e17ee1eSKristof Umann                             if (coin()) {
1085e17ee1eSKristof Umann                               x = 5;
1095e17ee1eSKristof Umann                             }
1105e17ee1eSKristof Umann                             int j = 10 / x;
1115e17ee1eSKristof Umann                             (void)j;
1125e17ee1eSKristof Umann                           }
1135e17ee1eSKristof Umann                         };)";
1145e17ee1eSKristof Umann   BuildResult Result = BuildCFG(Code);
1155e17ee1eSKristof Umann   EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
1165e17ee1eSKristof Umann 
1175e17ee1eSKristof Umann   //                  1st if  2nd if
1185e17ee1eSKristof Umann   //  [B5 (ENTRY)]  -> [B4] -> [B3] -> [B2] -> [B1] -> [B0 (EXIT)]
1195e17ee1eSKristof Umann   //                    \        \              /         /
1205e17ee1eSKristof Umann   //                     \        ------------->         /
1215e17ee1eSKristof Umann   //                      ------------------------------>
1225e17ee1eSKristof Umann 
1235e17ee1eSKristof Umann   CFG *cfg = Result.getCFG();
1245e17ee1eSKristof Umann 
125*c79345fbSZarko Todorovski   // Basic correctness checks.
1265e17ee1eSKristof Umann   EXPECT_EQ(cfg->size(), 6u);
1275e17ee1eSKristof Umann 
1285e17ee1eSKristof Umann   CFGBlock *ExitBlock = *cfg->begin();
1295e17ee1eSKristof Umann   EXPECT_EQ(ExitBlock, &cfg->getExit());
1305e17ee1eSKristof Umann 
1315e17ee1eSKristof Umann   CFGBlock *NullDerefBlock = *(cfg->begin() + 1);
1325e17ee1eSKristof Umann 
1335e17ee1eSKristof Umann   CFGBlock *SecondThenBlock = *(cfg->begin() + 2);
1345e17ee1eSKristof Umann 
1355e17ee1eSKristof Umann   CFGBlock *SecondIfBlock = *(cfg->begin() + 3);
1365e17ee1eSKristof Umann 
1375e17ee1eSKristof Umann   CFGBlock *FirstIfBlock = *(cfg->begin() + 4);
1385e17ee1eSKristof Umann 
1395e17ee1eSKristof Umann   CFGBlock *EntryBlock = *(cfg->begin() + 5);
1405e17ee1eSKristof Umann   EXPECT_EQ(EntryBlock, &cfg->getEntry());
1415e17ee1eSKristof Umann 
1425e17ee1eSKristof Umann   ControlDependencyCalculator Control(cfg);
1435e17ee1eSKristof Umann 
1445e17ee1eSKristof Umann   EXPECT_TRUE(Control.isControlDependent(SecondThenBlock, SecondIfBlock));
1455e17ee1eSKristof Umann   EXPECT_TRUE(Control.isControlDependent(SecondIfBlock, FirstIfBlock));
1465e17ee1eSKristof Umann   EXPECT_FALSE(Control.isControlDependent(NullDerefBlock, SecondIfBlock));
1475e17ee1eSKristof Umann }
1485e17ee1eSKristof Umann 
TEST(CFGDominatorTree,ControlDependencyWithLoops)1495e17ee1eSKristof Umann TEST(CFGDominatorTree, ControlDependencyWithLoops) {
1505e17ee1eSKristof Umann   const char *Code = R"(int test3() {
1515e17ee1eSKristof Umann                           int x,y,z;
1525e17ee1eSKristof Umann 
1535e17ee1eSKristof Umann                           x = y = z = 1;
1545e17ee1eSKristof Umann                           if (x > 0) {
1555e17ee1eSKristof Umann                             while (x >= 0){
1565e17ee1eSKristof Umann                               while (y >= x) {
1575e17ee1eSKristof Umann                                 x = x-1;
1585e17ee1eSKristof Umann                                 y = y/2;
1595e17ee1eSKristof Umann                               }
1605e17ee1eSKristof Umann                             }
1615e17ee1eSKristof Umann                           }
1625e17ee1eSKristof Umann                           z = y;
1635e17ee1eSKristof Umann 
1645e17ee1eSKristof Umann                           return 0;
1655e17ee1eSKristof Umann                         })";
1665e17ee1eSKristof Umann   BuildResult Result = BuildCFG(Code);
1675e17ee1eSKristof Umann   EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
1685e17ee1eSKristof Umann 
1695e17ee1eSKristof Umann   //                           <- [B2] <-
1705e17ee1eSKristof Umann   //                          /          \
1715e17ee1eSKristof Umann   // [B8 (ENTRY)] -> [B7] -> [B6] ---> [B5] -> [B4] -> [B3]
1725e17ee1eSKristof Umann   //                   \       |         \              /
1735e17ee1eSKristof Umann   //                    \      |          <-------------
1745e17ee1eSKristof Umann   //                     \      \
1755e17ee1eSKristof Umann   //                      --------> [B1] -> [B0 (EXIT)]
1765e17ee1eSKristof Umann 
1775e17ee1eSKristof Umann   CFG *cfg = Result.getCFG();
1785e17ee1eSKristof Umann 
1795e17ee1eSKristof Umann   ControlDependencyCalculator Control(cfg);
1805e17ee1eSKristof Umann 
1815e17ee1eSKristof Umann   auto GetBlock = [cfg] (unsigned Index) -> CFGBlock * {
1825e17ee1eSKristof Umann     assert(Index < cfg->size());
1835e17ee1eSKristof Umann     return *(cfg->begin() + Index);
1845e17ee1eSKristof Umann   };
1855e17ee1eSKristof Umann 
1865e17ee1eSKristof Umann   // While not immediately obvious, the second block in fact post dominates the
1875e17ee1eSKristof Umann   // fifth, hence B5 is not a control dependency of 2.
1885e17ee1eSKristof Umann   EXPECT_FALSE(Control.isControlDependent(GetBlock(5), GetBlock(2)));
1895e17ee1eSKristof Umann }
1905e17ee1eSKristof Umann 
1915e17ee1eSKristof Umann 
1922e2db937SKristof Umann } // namespace
1932e2db937SKristof Umann } // namespace analysis
1942e2db937SKristof Umann } // namespace clang
195