[llvm] 6af859d - [DebugInfo] Re-implement LexicalScopes dominance method, add unit tests

Jeremy Morse via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 28 03:45:34 PST 2020


Author: Jeremy Morse
Date: 2020-02-28T11:41:28Z
New Revision: 6af859dcca272cf3706d070183562e4cecb1dc36

URL: https://github.com/llvm/llvm-project/commit/6af859dcca272cf3706d070183562e4cecb1dc36
DIFF: https://github.com/llvm/llvm-project/commit/6af859dcca272cf3706d070183562e4cecb1dc36.diff

LOG: [DebugInfo] Re-implement LexicalScopes dominance method, add unit tests

Way back in D24994, the combination of LexicalScopes::dominates and
LiveDebugValues was identified as having worst-case quadratic complexity,
but it wasn't triggered by any code path at the time. I've since run into a
scenario where this occurs, in a very large basic block where large numbers
of inlined DBG_VALUEs are present.

The quadratic-ness comes from LiveDebugValues::join calling "dominates" on
every variable location, and LexicalScopes::dominates potentially touching
every instruction in a block to test for the presence of a scope. We have,
however, already computed the presence of scopes in blocks, in the
"InstrRanges" of each scope. This patch switches the dominates method to
examine whether a block is present in a scope's InsnRanges, avoiding
walking through the whole block.

At the same time, fix getMachineBasicBlocks to account for the fact that
InsnRanges can cover multiple blocks, and add some unit tests, as Lexical
Scopes didn't have any.

Differential revision: https://reviews.llvm.org/D73725

Added: 
    llvm/unittests/CodeGen/LexicalScopesTest.cpp
    llvm/unittests/CodeGen/MFCommon.inc

Modified: 
    llvm/lib/CodeGen/LexicalScopes.cpp
    llvm/unittests/CodeGen/CMakeLists.txt
    llvm/unittests/CodeGen/MachineInstrTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/LexicalScopes.cpp b/llvm/lib/CodeGen/LexicalScopes.cpp
index ac3ef0e709f3..be1d4c867516 100644
--- a/llvm/lib/CodeGen/LexicalScopes.cpp
+++ b/llvm/lib/CodeGen/LexicalScopes.cpp
@@ -291,9 +291,15 @@ void LexicalScopes::getMachineBasicBlocks(
     return;
   }
 
+  // The scope ranges can cover multiple basic blocks in each span. Iterate over
+  // all blocks (in the order they are in the function) until we reach the one
+  // containing the end of the span.
   SmallVectorImpl<InsnRange> &InsnRanges = Scope->getRanges();
   for (auto &R : InsnRanges)
-    MBBs.insert(R.first->getParent());
+    for (auto CurMBBIt = R.first->getParent()->getIterator(),
+              EndBBIt = std::next(R.second->getParent()->getIterator());
+         CurMBBIt != EndBBIt; CurMBBIt++)
+      MBBs.insert(&*CurMBBIt);
 }
 
 /// dominates - Return true if DebugLoc's lexical scope dominates at least one
@@ -308,14 +314,12 @@ bool LexicalScopes::dominates(const DILocation *DL, MachineBasicBlock *MBB) {
   if (Scope == CurrentFnLexicalScope && MBB->getParent() == MF)
     return true;
 
-  bool Result = false;
-  for (auto &I : *MBB) {
-    if (const DILocation *IDL = I.getDebugLoc())
-      if (LexicalScope *IScope = getOrCreateLexicalScope(IDL))
-        if (Scope->dominates(IScope))
-          return true;
-  }
-  return Result;
+  // Fetch all the blocks in DLs scope. Because the range / block list also
+  // contain any subscopes, any instruction that DL dominates can be found
+  // in the block set.
+  SmallPtrSet<const MachineBasicBlock *, 32> Set;
+  getMachineBasicBlocks(DL, Set);
+  return Set.count(MBB) != 0;
 }
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

diff  --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index fc8cd22bcc7c..fa3cb1fa7669 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -16,6 +16,7 @@ add_llvm_unittest(CodeGenTests
   AArch64SelectionDAGTest.cpp
   DIEHashTest.cpp
   LowLevelTypeTest.cpp
+  LexicalScopesTest.cpp
   MachineInstrBundleIteratorTest.cpp
   MachineInstrTest.cpp
   MachineOperandTest.cpp

diff  --git a/llvm/unittests/CodeGen/LexicalScopesTest.cpp b/llvm/unittests/CodeGen/LexicalScopesTest.cpp
new file mode 100644
index 000000000000..20975a775bf7
--- /dev/null
+++ b/llvm/unittests/CodeGen/LexicalScopesTest.cpp
@@ -0,0 +1,459 @@
+//===----------- llvm/unittest/CodeGen/LexicalScopesTest.cpp --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/LexicalScopes.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/TargetFrameLowering.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/IR/DIBuilder.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/ModuleSlotTracker.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+// Include helper functions to ease the manipulation of MachineFunctions
+#include "MFCommon.inc"
+
+class LexicalScopesTest : public testing::Test {
+public:
+  // Boilerplate,
+  LLVMContext Ctx;
+  Module Mod;
+  std::unique_ptr<MachineFunction> MF;
+  DICompileUnit *OurCU;
+  DIFile *OurFile;
+  DISubprogram *OurFunc;
+  DILexicalBlock *OurBlock, *AnotherBlock;
+  DISubprogram *ToInlineFunc;
+  DILexicalBlock *ToInlineBlock;
+  // DebugLocs that we'll used to create test environments.
+  DebugLoc OutermostLoc, InBlockLoc, NotNestedBlockLoc, InlinedLoc;
+
+  // Test environment blocks -- these form a diamond control flow pattern,
+  // MBB1 being the entry block, blocks two and three being the branches, and
+  // block four joining the branches and being an exit block.
+  MachineBasicBlock *MBB1, *MBB2, *MBB3, *MBB4;
+
+  // Some meaningless instructions -- the first is fully meaningless,
+  // while the second is supposed to impersonate DBG_VALUEs through its
+  // opcode.
+  MCInstrDesc BeanInst;
+  MCInstrDesc DbgValueInst;
+
+  LexicalScopesTest() : Ctx(), Mod("beehives", Ctx) {
+    memset(&BeanInst, 0, sizeof(BeanInst));
+    BeanInst.Opcode = 1;
+    BeanInst.Size = 1;
+
+    memset(&DbgValueInst, 0, sizeof(DbgValueInst));
+    DbgValueInst.Opcode = TargetOpcode::DBG_VALUE;
+    DbgValueInst.Size = 1;
+
+    // Boilerplate that creates a MachineFunction and associated blocks.
+    MF = createMachineFunction(Ctx, Mod);
+    llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
+    auto BB1 = BasicBlock::Create(Ctx, "a", &F);
+    auto BB2 = BasicBlock::Create(Ctx, "b", &F);
+    auto BB3 = BasicBlock::Create(Ctx, "c", &F);
+    auto BB4 = BasicBlock::Create(Ctx, "d", &F);
+    IRBuilder<> IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
+    IRB1.CreateBr(BB2);
+    IRB2.CreateBr(BB3);
+    IRB3.CreateBr(BB4);
+    IRB4.CreateRetVoid();
+    MBB1 = MF->CreateMachineBasicBlock(BB1);
+    MF->insert(MF->end(), MBB1);
+    MBB2 = MF->CreateMachineBasicBlock(BB2);
+    MF->insert(MF->end(), MBB2);
+    MBB3 = MF->CreateMachineBasicBlock(BB3);
+    MF->insert(MF->end(), MBB3);
+    MBB4 = MF->CreateMachineBasicBlock(BB4);
+    MF->insert(MF->end(), MBB4);
+    MBB1->addSuccessor(MBB2);
+    MBB1->addSuccessor(MBB3);
+    MBB2->addSuccessor(MBB4);
+    MBB3->addSuccessor(MBB4);
+
+    // Create metadata: CU, subprogram, some blocks and an inline function
+    // scope.
+    DIBuilder DIB(Mod);
+    OurFile = DIB.createFile("xyzzy.c", "/cave");
+    OurCU =
+        DIB.createCompileUnit(dwarf::DW_LANG_C99, OurFile, "nou", false, "", 0);
+    auto OurSubT = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
+    OurFunc =
+        DIB.createFunction(OurCU, "bees", "", OurFile, 1, OurSubT, 1,
+                           DINode::FlagZero, DISubprogram::SPFlagDefinition);
+    F.setSubprogram(OurFunc);
+    OurBlock = DIB.createLexicalBlock(OurFunc, OurFile, 2, 3);
+    AnotherBlock = DIB.createLexicalBlock(OurFunc, OurFile, 2, 6);
+    ToInlineFunc =
+        DIB.createFunction(OurFile, "shoes", "", OurFile, 10, OurSubT, 10,
+                           DINode::FlagZero, DISubprogram::SPFlagDefinition);
+
+    // Make some nested scopes.
+    OutermostLoc = DebugLoc::get(3, 1, OurFunc);
+    InBlockLoc = DebugLoc::get(4, 1, OurBlock);
+    InlinedLoc = DebugLoc::get(10, 1, ToInlineFunc, InBlockLoc.get());
+
+    // Make a scope that isn't nested within the others.
+    NotNestedBlockLoc = DebugLoc::get(4, 1, AnotherBlock);
+
+    DIB.finalize();
+  }
+};
+
+// Fill blocks with dummy instructions, test some base lexical scope
+// functionaliy.
+TEST_F(LexicalScopesTest, FlatLayout) {
+  BuildMI(*MBB1, MBB1->end(), OutermostLoc, BeanInst);
+  BuildMI(*MBB2, MBB2->end(), OutermostLoc, BeanInst);
+  BuildMI(*MBB3, MBB3->end(), OutermostLoc, BeanInst);
+  BuildMI(*MBB4, MBB4->end(), OutermostLoc, BeanInst);
+
+  LexicalScopes LS;
+  EXPECT_TRUE(LS.empty());
+  LS.reset();
+  EXPECT_EQ(LS.getCurrentFunctionScope(), nullptr);
+
+  LS.initialize(*MF);
+  EXPECT_FALSE(LS.empty());
+  LexicalScope *FuncScope = LS.getCurrentFunctionScope();
+  EXPECT_EQ(FuncScope->getParent(), nullptr);
+  EXPECT_EQ(FuncScope->getDesc(), OurFunc);
+  EXPECT_EQ(FuncScope->getInlinedAt(), nullptr);
+  EXPECT_EQ(FuncScope->getScopeNode(), OurFunc);
+  EXPECT_FALSE(FuncScope->isAbstractScope());
+  EXPECT_EQ(FuncScope->getChildren().size(), 0u);
+
+  // There should be one range, covering the whole function. Test that it
+  // points at the correct instructions.
+  auto &Ranges = FuncScope->getRanges();
+  ASSERT_EQ(Ranges.size(), 1u);
+  EXPECT_EQ(Ranges.front().first, &*MF->begin()->begin());
+  auto BBIt = MF->end();
+  BBIt = std::prev(BBIt);
+  EXPECT_EQ(Ranges.front().second, &*BBIt->begin());
+
+  EXPECT_TRUE(FuncScope->dominates(FuncScope));
+  SmallPtrSet<const MachineBasicBlock *, 4> MBBVec;
+  LS.getMachineBasicBlocks(OutermostLoc.get(), MBBVec);
+
+  EXPECT_EQ(MBBVec.size(), 4u);
+  // All the blocks should be in that set; the outermost loc should dominate
+  // them; and no other scope should.
+  for (auto &MBB : *MF) {
+    EXPECT_EQ(MBBVec.count(&MBB), 1u);
+    EXPECT_TRUE(LS.dominates(OutermostLoc.get(), &MBB));
+    EXPECT_FALSE(LS.dominates(InBlockLoc.get(), &MBB));
+    EXPECT_FALSE(LS.dominates(InlinedLoc.get(), &MBB));
+  }
+}
+
+// Examine relationship between two nested scopes inside the function, the
+// outer function and the lexical block within it.
+TEST_F(LexicalScopesTest, BlockScopes) {
+  BuildMI(*MBB1, MBB1->end(), InBlockLoc, BeanInst);
+  BuildMI(*MBB2, MBB2->end(), InBlockLoc, BeanInst);
+  BuildMI(*MBB3, MBB3->end(), InBlockLoc, BeanInst);
+  BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst);
+
+  LexicalScopes LS;
+  LS.initialize(*MF);
+  LexicalScope *FuncScope = LS.getCurrentFunctionScope();
+  EXPECT_EQ(FuncScope->getDesc(), OurFunc);
+  auto &Children = FuncScope->getChildren();
+  ASSERT_EQ(Children.size(), 1u);
+  auto *BlockScope = Children[0];
+  EXPECT_EQ(LS.findLexicalScope(InBlockLoc.get()), BlockScope);
+  EXPECT_EQ(BlockScope->getDesc(), InBlockLoc->getScope());
+  EXPECT_FALSE(BlockScope->isAbstractScope());
+
+  EXPECT_TRUE(FuncScope->dominates(BlockScope));
+  EXPECT_FALSE(BlockScope->dominates(FuncScope));
+  EXPECT_EQ(FuncScope->getParent(), nullptr);
+  EXPECT_EQ(BlockScope->getParent(), FuncScope);
+
+  SmallPtrSet<const MachineBasicBlock *, 4> MBBVec;
+  LS.getMachineBasicBlocks(OutermostLoc.get(), MBBVec);
+
+  EXPECT_EQ(MBBVec.size(), 4u);
+  for (auto &MBB : *MF) {
+    EXPECT_EQ(MBBVec.count(&MBB), 1u);
+    EXPECT_TRUE(LS.dominates(OutermostLoc.get(), &MBB));
+    EXPECT_TRUE(LS.dominates(InBlockLoc.get(), &MBB));
+    EXPECT_FALSE(LS.dominates(InlinedLoc.get(), &MBB));
+  }
+}
+
+// Test inlined scopes functionality and relationship with the outer scopes.
+TEST_F(LexicalScopesTest, InlinedScopes) {
+  BuildMI(*MBB1, MBB1->end(), InlinedLoc, BeanInst);
+  BuildMI(*MBB2, MBB2->end(), InlinedLoc, BeanInst);
+  BuildMI(*MBB3, MBB3->end(), InlinedLoc, BeanInst);
+  BuildMI(*MBB4, MBB4->end(), InlinedLoc, BeanInst);
+
+  LexicalScopes LS;
+  LS.initialize(*MF);
+  LexicalScope *FuncScope = LS.getCurrentFunctionScope();
+  auto &Children = FuncScope->getChildren();
+  ASSERT_EQ(Children.size(), 1u);
+  auto *BlockScope = Children[0];
+  auto &BlockChildren = BlockScope->getChildren();
+  ASSERT_EQ(BlockChildren.size(), 1u);
+  auto *InlinedScope = BlockChildren[0];
+
+  EXPECT_FALSE(InlinedScope->isAbstractScope());
+  EXPECT_EQ(InlinedScope->getInlinedAt(), InlinedLoc.getInlinedAt());
+  EXPECT_EQ(InlinedScope->getDesc(), InlinedLoc.getScope());
+  EXPECT_EQ(InlinedScope->getChildren().size(), 0u);
+
+  EXPECT_EQ(FuncScope->getParent(), nullptr);
+  EXPECT_EQ(BlockScope->getParent(), FuncScope);
+  EXPECT_EQ(InlinedScope->getParent(), BlockScope);
+
+  const auto &AbstractScopes = LS.getAbstractScopesList();
+  ASSERT_EQ(AbstractScopes.size(), 1u);
+  const auto &AbstractScope = *AbstractScopes[0];
+  EXPECT_TRUE(AbstractScope.isAbstractScope());
+  EXPECT_EQ(AbstractScope.getDesc(), InlinedLoc.getScope());
+  EXPECT_EQ(AbstractScope.getInlinedAt(), nullptr);
+  EXPECT_EQ(AbstractScope.getParent(), nullptr);
+}
+
+// Test behaviour in a function that has empty DebugLocs.
+TEST_F(LexicalScopesTest, FuncWithEmptyGap) {
+  BuildMI(*MBB1, MBB1->end(), OutermostLoc, BeanInst);
+  BuildMI(*MBB2, MBB2->end(), DebugLoc(), BeanInst);
+  BuildMI(*MBB3, MBB3->end(), DebugLoc(), BeanInst);
+  BuildMI(*MBB4, MBB4->end(), OutermostLoc, BeanInst);
+
+  LexicalScopes LS;
+  LS.initialize(*MF);
+  LexicalScope *FuncScope = LS.getCurrentFunctionScope();
+
+  // A gap in a range that contains no other location, is not actually a
+  // gap as far as lexical scopes are concerned.
+  auto &Ranges = FuncScope->getRanges();
+  ASSERT_EQ(Ranges.size(), 1u);
+  EXPECT_EQ(Ranges[0].first, &*MF->begin()->begin());
+  auto BBIt = MF->end();
+  BBIt = std::prev(BBIt);
+  EXPECT_EQ(Ranges[0].second, &*BBIt->begin());
+}
+
+// Now a function with intervening not-in-scope instructions.
+TEST_F(LexicalScopesTest, FuncWithRealGap) {
+  MachineInstr *FirstI = BuildMI(*MBB1, MBB1->end(), InBlockLoc, BeanInst);
+  BuildMI(*MBB2, MBB2->end(), OutermostLoc, BeanInst);
+  BuildMI(*MBB3, MBB3->end(), OutermostLoc, BeanInst);
+  MachineInstr *LastI = BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst);
+
+  LexicalScopes LS;
+  LS.initialize(*MF);
+  LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get());
+  ASSERT_NE(BlockScope, nullptr);
+
+  // Within the block scope, there's a gap between the first and last
+  // block / instruction, where it's only the outermost scope.
+  auto &Ranges = BlockScope->getRanges();
+  ASSERT_EQ(Ranges.size(), 2u);
+  EXPECT_EQ(Ranges[0].first, FirstI);
+  EXPECT_EQ(Ranges[0].second, FirstI);
+  EXPECT_EQ(Ranges[1].first, LastI);
+  EXPECT_EQ(Ranges[1].second, LastI);
+
+  // The outer function scope should cover the whole function, including
+  // blocks the lexicalblock covers.
+  LexicalScope *FuncScope = LS.getCurrentFunctionScope();
+  auto &FuncRanges = FuncScope->getRanges();
+  ASSERT_EQ(FuncRanges.size(), 1u);
+  EXPECT_NE(FuncRanges[0].first, FuncRanges[0].second);
+  EXPECT_EQ(FuncRanges[0].first, FirstI);
+  EXPECT_EQ(FuncRanges[0].second, LastI);
+}
+
+// Examine the relationship between two scopes that don't nest (are siblings).
+TEST_F(LexicalScopesTest, NotNested) {
+  MachineInstr *FirstI = BuildMI(*MBB1, MBB1->end(), InBlockLoc, BeanInst);
+  MachineInstr *SecondI =
+      BuildMI(*MBB2, MBB2->end(), NotNestedBlockLoc, BeanInst);
+  MachineInstr *ThirdI =
+      BuildMI(*MBB3, MBB3->end(), NotNestedBlockLoc, BeanInst);
+  MachineInstr *FourthI = BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst);
+
+  LexicalScopes LS;
+  LS.initialize(*MF);
+  LexicalScope *FuncScope = LS.getCurrentFunctionScope();
+  LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get());
+  LexicalScope *OtherBlockScope = LS.findLexicalScope(NotNestedBlockLoc.get());
+  ASSERT_NE(FuncScope, nullptr);
+  ASSERT_NE(BlockScope, nullptr);
+  ASSERT_NE(OtherBlockScope, nullptr);
+
+  // The function should cover everything; the two blocks are distinct and
+  // should not.
+  auto &FuncRanges = FuncScope->getRanges();
+  ASSERT_EQ(FuncRanges.size(), 1u);
+  EXPECT_EQ(FuncRanges[0].first, FirstI);
+  EXPECT_EQ(FuncRanges[0].second, FourthI);
+
+  // Two ranges, start and end instructions.
+  auto &BlockRanges = BlockScope->getRanges();
+  ASSERT_EQ(BlockRanges.size(), 2u);
+  EXPECT_EQ(BlockRanges[0].first, FirstI);
+  EXPECT_EQ(BlockRanges[0].second, FirstI);
+  EXPECT_EQ(BlockRanges[1].first, FourthI);
+  EXPECT_EQ(BlockRanges[1].second, FourthI);
+
+  // One inner range, covering the two inner blocks.
+  auto &OtherBlockRanges = OtherBlockScope->getRanges();
+  ASSERT_EQ(OtherBlockRanges.size(), 1u);
+  EXPECT_EQ(OtherBlockRanges[0].first, SecondI);
+  EXPECT_EQ(OtherBlockRanges[0].second, ThirdI);
+}
+
+// Test the scope-specific and block-specific dominates methods.
+TEST_F(LexicalScopesTest, TestDominates) {
+  BuildMI(*MBB1, MBB1->end(), InBlockLoc, BeanInst);
+  BuildMI(*MBB2, MBB2->end(), NotNestedBlockLoc, BeanInst);
+  BuildMI(*MBB3, MBB3->end(), NotNestedBlockLoc, BeanInst);
+  BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst);
+
+  LexicalScopes LS;
+  LS.initialize(*MF);
+  LexicalScope *FuncScope = LS.getCurrentFunctionScope();
+  LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get());
+  LexicalScope *OtherBlockScope = LS.findLexicalScope(NotNestedBlockLoc.get());
+  ASSERT_NE(FuncScope, nullptr);
+  ASSERT_NE(BlockScope, nullptr);
+  ASSERT_NE(OtherBlockScope, nullptr);
+
+  EXPECT_TRUE(FuncScope->dominates(BlockScope));
+  EXPECT_TRUE(FuncScope->dominates(OtherBlockScope));
+  EXPECT_FALSE(BlockScope->dominates(FuncScope));
+  EXPECT_FALSE(BlockScope->dominates(OtherBlockScope));
+  EXPECT_FALSE(OtherBlockScope->dominates(FuncScope));
+  EXPECT_FALSE(OtherBlockScope->dominates(BlockScope));
+
+  // Outermost scope dominates everything, as all insts are within it.
+  EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB1));
+  EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB2));
+  EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB3));
+  EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB4));
+
+  // One inner block dominates the outer pair of blocks,
+  EXPECT_TRUE(LS.dominates(InBlockLoc.get(), MBB1));
+  EXPECT_FALSE(LS.dominates(InBlockLoc.get(), MBB2));
+  EXPECT_FALSE(LS.dominates(InBlockLoc.get(), MBB3));
+  EXPECT_TRUE(LS.dominates(InBlockLoc.get(), MBB4));
+
+  // While the other dominates the inner two blocks.
+  EXPECT_FALSE(LS.dominates(NotNestedBlockLoc.get(), MBB1));
+  EXPECT_TRUE(LS.dominates(NotNestedBlockLoc.get(), MBB2));
+  EXPECT_TRUE(LS.dominates(NotNestedBlockLoc.get(), MBB3));
+  EXPECT_FALSE(LS.dominates(NotNestedBlockLoc.get(), MBB4));
+}
+
+// Test getMachineBasicBlocks returns all dominated blocks.
+TEST_F(LexicalScopesTest, TestGetBlocks) {
+  BuildMI(*MBB1, MBB1->end(), InBlockLoc, BeanInst);
+  BuildMI(*MBB2, MBB2->end(), NotNestedBlockLoc, BeanInst);
+  BuildMI(*MBB3, MBB3->end(), NotNestedBlockLoc, BeanInst);
+  BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst);
+
+  LexicalScopes LS;
+  LS.initialize(*MF);
+  LexicalScope *FuncScope = LS.getCurrentFunctionScope();
+  LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get());
+  LexicalScope *OtherBlockScope = LS.findLexicalScope(NotNestedBlockLoc.get());
+  ASSERT_NE(FuncScope, nullptr);
+  ASSERT_NE(BlockScope, nullptr);
+  ASSERT_NE(OtherBlockScope, nullptr);
+
+  SmallPtrSet<const MachineBasicBlock *, 4> OutermostBlocks, InBlockBlocks,
+      NotNestedBlockBlocks;
+  LS.getMachineBasicBlocks(OutermostLoc.get(), OutermostBlocks);
+  LS.getMachineBasicBlocks(InBlockLoc.get(), InBlockBlocks);
+  LS.getMachineBasicBlocks(NotNestedBlockLoc.get(), NotNestedBlockBlocks);
+
+  EXPECT_EQ(OutermostBlocks.count(MBB1), 1u);
+  EXPECT_EQ(OutermostBlocks.count(MBB2), 1u);
+  EXPECT_EQ(OutermostBlocks.count(MBB3), 1u);
+  EXPECT_EQ(OutermostBlocks.count(MBB4), 1u);
+
+  EXPECT_EQ(InBlockBlocks.count(MBB1), 1u);
+  EXPECT_EQ(InBlockBlocks.count(MBB2), 0u);
+  EXPECT_EQ(InBlockBlocks.count(MBB3), 0u);
+  EXPECT_EQ(InBlockBlocks.count(MBB4), 1u);
+
+  EXPECT_EQ(NotNestedBlockBlocks.count(MBB1), 0u);
+  EXPECT_EQ(NotNestedBlockBlocks.count(MBB2), 1u);
+  EXPECT_EQ(NotNestedBlockBlocks.count(MBB3), 1u);
+  EXPECT_EQ(NotNestedBlockBlocks.count(MBB4), 0u);
+}
+
+TEST_F(LexicalScopesTest, TestMetaInst) {
+  // Instruction Layout looks like this, where 'F' means funcscope, and
+  // 'B' blockscope:
+  // bb1:
+  //   F: bean
+  //   B: bean
+  // bb2:
+  //   F: bean
+  //   B: DBG_VALUE
+  // bb3:
+  //   F: bean
+  //   B: DBG_VALUE
+  // bb4:
+  //   F: bean
+  //   B: bean
+  // The block / 'B' should only dominate bb1 and bb4. DBG_VALUE is a meta
+  // instruction, and shouldn't contribute to scopes.
+  BuildMI(*MBB1, MBB1->end(), OutermostLoc, BeanInst);
+  BuildMI(*MBB1, MBB1->end(), InBlockLoc, BeanInst);
+  BuildMI(*MBB2, MBB2->end(), OutermostLoc, BeanInst);
+  BuildMI(*MBB2, MBB2->end(), InBlockLoc, DbgValueInst);
+  BuildMI(*MBB3, MBB3->end(), OutermostLoc, BeanInst);
+  BuildMI(*MBB3, MBB3->end(), InBlockLoc, DbgValueInst);
+  BuildMI(*MBB4, MBB4->end(), OutermostLoc, BeanInst);
+  BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst);
+
+  LexicalScopes LS;
+  LS.initialize(*MF);
+  LexicalScope *FuncScope = LS.getCurrentFunctionScope();
+  LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get());
+  ASSERT_NE(FuncScope, nullptr);
+  ASSERT_NE(BlockScope, nullptr);
+
+  EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB1));
+  EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB2));
+  EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB3));
+  EXPECT_TRUE(LS.dominates(OutermostLoc.get(), MBB4));
+  EXPECT_TRUE(LS.dominates(InBlockLoc.get(), MBB1));
+  EXPECT_FALSE(LS.dominates(InBlockLoc.get(), MBB2));
+  EXPECT_FALSE(LS.dominates(InBlockLoc.get(), MBB3));
+  EXPECT_TRUE(LS.dominates(InBlockLoc.get(), MBB4));
+}
+
+} // anonymous namespace

diff  --git a/llvm/unittests/CodeGen/MFCommon.inc b/llvm/unittests/CodeGen/MFCommon.inc
new file mode 100644
index 000000000000..7468ff28fa94
--- /dev/null
+++ b/llvm/unittests/CodeGen/MFCommon.inc
@@ -0,0 +1,128 @@
+// Add a few Bogus backend classes so we can create MachineInstrs without
+// depending on a real target.
+class BogusTargetLowering : public TargetLowering {
+public:
+  BogusTargetLowering(TargetMachine &TM) : TargetLowering(TM) {}
+};
+
+class BogusFrameLowering : public TargetFrameLowering {
+public:
+  BogusFrameLowering()
+      : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 4) {}
+
+  void emitPrologue(MachineFunction &MF,
+                    MachineBasicBlock &MBB) const override {}
+  void emitEpilogue(MachineFunction &MF,
+                    MachineBasicBlock &MBB) const override {}
+  bool hasFP(const MachineFunction &MF) const override { return false; }
+};
+
+static TargetRegisterClass *const BogusRegisterClasses[] = {nullptr};
+
+class BogusRegisterInfo : public TargetRegisterInfo {
+public:
+  BogusRegisterInfo()
+      : TargetRegisterInfo(nullptr, BogusRegisterClasses, BogusRegisterClasses,
+                           nullptr, nullptr, LaneBitmask(~0u), nullptr) {
+    InitMCRegisterInfo(nullptr, 0, 0, 0, nullptr, 0, nullptr, 0, nullptr,
+                       nullptr, nullptr, nullptr, nullptr, 0, nullptr, nullptr);
+  }
+
+  const MCPhysReg *
+  getCalleeSavedRegs(const MachineFunction *MF) const override {
+    return nullptr;
+  }
+  ArrayRef<const uint32_t *> getRegMasks() const override { return None; }
+  ArrayRef<const char *> getRegMaskNames() const override { return None; }
+  BitVector getReservedRegs(const MachineFunction &MF) const override {
+    return BitVector();
+  }
+  const RegClassWeight &
+  getRegClassWeight(const TargetRegisterClass *RC) const override {
+    static RegClassWeight Bogus{1, 16};
+    return Bogus;
+  }
+  unsigned getRegUnitWeight(unsigned RegUnit) const override { return 1; }
+  unsigned getNumRegPressureSets() const override { return 0; }
+  const char *getRegPressureSetName(unsigned Idx) const override {
+    return "bogus";
+  }
+  unsigned getRegPressureSetLimit(const MachineFunction &MF,
+                                  unsigned Idx) const override {
+    return 0;
+  }
+  const int *
+  getRegClassPressureSets(const TargetRegisterClass *RC) const override {
+    static const int Bogus[] = {0, -1};
+    return &Bogus[0];
+  }
+  const int *getRegUnitPressureSets(unsigned RegUnit) const override {
+    static const int Bogus[] = {0, -1};
+    return &Bogus[0];
+  }
+
+  Register getFrameRegister(const MachineFunction &MF) const override {
+    return 0;
+  }
+  void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
+                           unsigned FIOperandNum,
+                           RegScavenger *RS = nullptr) const override {}
+};
+
+class BogusSubtarget : public TargetSubtargetInfo {
+public:
+  BogusSubtarget(TargetMachine &TM)
+      : TargetSubtargetInfo(Triple(""), "", "", {}, {}, nullptr, nullptr,
+                            nullptr, nullptr, nullptr, nullptr),
+        FL(), TL(TM) {}
+  ~BogusSubtarget() override {}
+
+  const TargetFrameLowering *getFrameLowering() const override { return &FL; }
+
+  const TargetLowering *getTargetLowering() const override { return &TL; }
+
+  const TargetInstrInfo *getInstrInfo() const override { return &TII; }
+
+  const TargetRegisterInfo *getRegisterInfo() const override { return &TRI; }
+
+private:
+  BogusFrameLowering FL;
+  BogusRegisterInfo TRI;
+  BogusTargetLowering TL;
+  TargetInstrInfo TII;
+};
+
+class BogusTargetMachine : public LLVMTargetMachine {
+public:
+  BogusTargetMachine()
+      : LLVMTargetMachine(Target(), "", Triple(""), "", "", TargetOptions(),
+                          Reloc::Static, CodeModel::Small, CodeGenOpt::Default),
+        ST(*this) {}
+
+  ~BogusTargetMachine() override {}
+
+  const TargetSubtargetInfo *getSubtargetImpl(const Function &) const override {
+    return &ST;
+  }
+
+private:
+  BogusSubtarget ST;
+};
+
+std::unique_ptr<BogusTargetMachine> createTargetMachine() {
+  return std::make_unique<BogusTargetMachine>();
+}
+
+std::unique_ptr<MachineFunction> createMachineFunction(LLVMContext &Ctx,
+                                                       Module &M) {
+  auto Type = FunctionType::get(Type::getVoidTy(Ctx), false);
+  auto F = Function::Create(Type, GlobalValue::ExternalLinkage, "Test", &M);
+
+  auto TM = createTargetMachine();
+  unsigned FunctionNum = 42;
+  MachineModuleInfo MMI(TM.get());
+  const TargetSubtargetInfo &STI = *TM->getSubtargetImpl(*F);
+
+  return std::make_unique<MachineFunction>(*F, *TM, STI, FunctionNum, MMI);
+}
+

diff  --git a/llvm/unittests/CodeGen/MachineInstrTest.cpp b/llvm/unittests/CodeGen/MachineInstrTest.cpp
index 90c8a4049e2a..4151ef7a6d00 100644
--- a/llvm/unittests/CodeGen/MachineInstrTest.cpp
+++ b/llvm/unittests/CodeGen/MachineInstrTest.cpp
@@ -16,6 +16,7 @@
 #include "llvm/CodeGen/TargetLowering.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/ModuleSlotTracker.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCSymbol.h"
@@ -28,144 +29,20 @@
 using namespace llvm;
 
 namespace {
-// Add a few Bogus backend classes so we can create MachineInstrs without
-// depending on a real target.
-class BogusTargetLowering : public TargetLowering {
-public:
-  BogusTargetLowering(TargetMachine &TM) : TargetLowering(TM) {}
-};
-
-class BogusFrameLowering : public TargetFrameLowering {
-public:
-  BogusFrameLowering()
-      : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(4), 4) {}
-
-  void emitPrologue(MachineFunction &MF,
-                    MachineBasicBlock &MBB) const override {}
-  void emitEpilogue(MachineFunction &MF,
-                    MachineBasicBlock &MBB) const override {}
-  bool hasFP(const MachineFunction &MF) const override { return false; }
-};
-
-static TargetRegisterClass *const BogusRegisterClasses[] = {nullptr};
-
-class BogusRegisterInfo : public TargetRegisterInfo {
-public:
-  BogusRegisterInfo()
-      : TargetRegisterInfo(nullptr, BogusRegisterClasses, BogusRegisterClasses,
-                           nullptr, nullptr, LaneBitmask(~0u), nullptr) {
-    InitMCRegisterInfo(nullptr, 0, 0, 0, nullptr, 0, nullptr, 0, nullptr,
-                       nullptr, nullptr, nullptr, nullptr, 0, nullptr, nullptr);
-  }
-
-  const MCPhysReg *
-  getCalleeSavedRegs(const MachineFunction *MF) const override {
-    return nullptr;
-  }
-  ArrayRef<const uint32_t *> getRegMasks() const override { return None; }
-  ArrayRef<const char *> getRegMaskNames() const override { return None; }
-  BitVector getReservedRegs(const MachineFunction &MF) const override {
-    return BitVector();
-  }
-  const RegClassWeight &
-  getRegClassWeight(const TargetRegisterClass *RC) const override {
-    static RegClassWeight Bogus{1, 16};
-    return Bogus;
-  }
-  unsigned getRegUnitWeight(unsigned RegUnit) const override { return 1; }
-  unsigned getNumRegPressureSets() const override { return 0; }
-  const char *getRegPressureSetName(unsigned Idx) const override {
-    return "bogus";
-  }
-  unsigned getRegPressureSetLimit(const MachineFunction &MF,
-                                  unsigned Idx) const override {
-    return 0;
-  }
-  const int *
-  getRegClassPressureSets(const TargetRegisterClass *RC) const override {
-    static const int Bogus[] = {0, -1};
-    return &Bogus[0];
-  }
-  const int *getRegUnitPressureSets(unsigned RegUnit) const override {
-    static const int Bogus[] = {0, -1};
-    return &Bogus[0];
-  }
-
-  Register getFrameRegister(const MachineFunction &MF) const override {
-    return 0;
-  }
-  void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
-                           unsigned FIOperandNum,
-                           RegScavenger *RS = nullptr) const override {}
-};
-
-class BogusSubtarget : public TargetSubtargetInfo {
-public:
-  BogusSubtarget(TargetMachine &TM)
-      : TargetSubtargetInfo(Triple(""), "", "", {}, {}, nullptr, nullptr,
-                            nullptr, nullptr, nullptr, nullptr),
-        FL(), TL(TM) {}
-  ~BogusSubtarget() override {}
-
-  const TargetFrameLowering *getFrameLowering() const override { return &FL; }
-
-  const TargetLowering *getTargetLowering() const override { return &TL; }
-
-  const TargetInstrInfo *getInstrInfo() const override { return &TII; }
-
-  const TargetRegisterInfo *getRegisterInfo() const override { return &TRI; }
-
-private:
-  BogusFrameLowering FL;
-  BogusRegisterInfo TRI;
-  BogusTargetLowering TL;
-  TargetInstrInfo TII;
-};
-
-class BogusTargetMachine : public LLVMTargetMachine {
-public:
-  BogusTargetMachine()
-      : LLVMTargetMachine(Target(), "", Triple(""), "", "", TargetOptions(),
-                          Reloc::Static, CodeModel::Small, CodeGenOpt::Default),
-        ST(*this) {}
-
-  ~BogusTargetMachine() override {}
-
-  const TargetSubtargetInfo *getSubtargetImpl(const Function &) const override {
-    return &ST;
-  }
-
-private:
-  BogusSubtarget ST;
-};
+// Include helper functions to ease the manipulation of MachineFunctions.
+#include "MFCommon.inc"
 
 std::unique_ptr<MCContext> createMCContext(MCAsmInfo *AsmInfo) {
   return std::make_unique<MCContext>(
       AsmInfo, nullptr, nullptr, nullptr, nullptr, false);
 }
 
-std::unique_ptr<BogusTargetMachine> createTargetMachine() {
-  return std::make_unique<BogusTargetMachine>();
-}
-
-std::unique_ptr<MachineFunction> createMachineFunction() {
-  LLVMContext Ctx;
-  Module M("Module", Ctx);
-  auto Type = FunctionType::get(Type::getVoidTy(Ctx), false);
-  auto F = Function::Create(Type, GlobalValue::ExternalLinkage, "Test", &M);
-
-  auto TM = createTargetMachine();
-  unsigned FunctionNum = 42;
-  MachineModuleInfo MMI(TM.get());
-  const TargetSubtargetInfo &STI = *TM->getSubtargetImpl(*F);
-
-  return std::make_unique<MachineFunction>(*F, *TM, STI, FunctionNum, MMI);
-}
-
 // This test makes sure that MachineInstr::isIdenticalTo handles Defs correctly
 // for various combinations of IgnoreDefs, and also that it is symmetrical.
 TEST(IsIdenticalToTest, DifferentDefs) {
-  auto MF = createMachineFunction();
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
 
   unsigned short NumOps = 2;
   unsigned char NumDefs = 1;
@@ -234,7 +111,9 @@ void checkHashAndIsEqualMatch(MachineInstr *MI1, MachineInstr *MI2) {
 // This test makes sure that MachineInstrExpressionTraits::isEqual is in sync
 // with MachineInstrExpressionTraits::getHashValue.
 TEST(MachineInstrExpressionTraitTest, IsEqualAgreesWithGetHashValue) {
-  auto MF = createMachineFunction();
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
 
   unsigned short NumOps = 2;
   unsigned char NumDefs = 1;
@@ -312,13 +191,14 @@ TEST(MachineInstrExpressionTraitTest, IsEqualAgreesWithGetHashValue) {
 }
 
 TEST(MachineInstrPrintingTest, DebugLocPrinting) {
-  auto MF = createMachineFunction();
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
 
   MCOperandInfo OpInfo{0, 0, MCOI::OPERAND_REGISTER, 0};
   MCInstrDesc MCID = {0, 1,       1,       0,       0, 0,
                       0, nullptr, nullptr, &OpInfo, 0, nullptr};
 
-  LLVMContext Ctx;
   DIFile *DIF = DIFile::getDistinct(Ctx, "filename", "");
   DISubprogram *DIS = DISubprogram::getDistinct(
       Ctx, nullptr, "", "", DIF, 0, nullptr, 0, nullptr, 0, 0, DINode::FlagZero,
@@ -339,7 +219,9 @@ TEST(MachineInstrPrintingTest, DebugLocPrinting) {
 }
 
 TEST(MachineInstrSpan, DistanceBegin) {
-  auto MF = createMachineFunction();
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
   auto MBB = MF->CreateMachineBasicBlock();
 
   MCInstrDesc MCID = {0, 0,       0,       0,       0, 0,
@@ -355,7 +237,9 @@ TEST(MachineInstrSpan, DistanceBegin) {
 }
 
 TEST(MachineInstrSpan, DistanceEnd) {
-  auto MF = createMachineFunction();
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
   auto MBB = MF->CreateMachineBasicBlock();
 
   MCInstrDesc MCID = {0, 0,       0,       0,       0, 0,
@@ -371,7 +255,9 @@ TEST(MachineInstrSpan, DistanceEnd) {
 }
 
 TEST(MachineInstrExtraInfo, AddExtraInfo) {
-  auto MF = createMachineFunction();
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
   MCInstrDesc MCID = {0, 0,       0,       0,       0, 0,
                       0, nullptr, nullptr, nullptr, 0, nullptr};
 
@@ -384,7 +270,6 @@ TEST(MachineInstrExtraInfo, AddExtraInfo) {
   MMOs.push_back(MMO);
   MCSymbol *Sym1 = MC->createTempSymbol("pre_label", false);
   MCSymbol *Sym2 = MC->createTempSymbol("post_label", false);
-  LLVMContext Ctx;
   MDNode *MDN = MDNode::getDistinct(Ctx, None);
 
   ASSERT_TRUE(MI->memoperands_empty());
@@ -418,7 +303,9 @@ TEST(MachineInstrExtraInfo, AddExtraInfo) {
 }
 
 TEST(MachineInstrExtraInfo, ChangeExtraInfo) {
-  auto MF = createMachineFunction();
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
   MCInstrDesc MCID = {0, 0,       0,       0,       0, 0,
                       0, nullptr, nullptr, nullptr, 0, nullptr};
 
@@ -431,7 +318,6 @@ TEST(MachineInstrExtraInfo, ChangeExtraInfo) {
   MMOs.push_back(MMO);
   MCSymbol *Sym1 = MC->createTempSymbol("pre_label", false);
   MCSymbol *Sym2 = MC->createTempSymbol("post_label", false);
-  LLVMContext Ctx;
   MDNode *MDN = MDNode::getDistinct(Ctx, None);
 
   MI->setMemRefs(*MF, MMOs);
@@ -455,7 +341,9 @@ TEST(MachineInstrExtraInfo, ChangeExtraInfo) {
 }
 
 TEST(MachineInstrExtraInfo, RemoveExtraInfo) {
-  auto MF = createMachineFunction();
+  LLVMContext Ctx;
+  Module Mod("Module", Ctx);
+  auto MF = createMachineFunction(Ctx, Mod);
   MCInstrDesc MCID = {0, 0,       0,       0,       0, 0,
                       0, nullptr, nullptr, nullptr, 0, nullptr};
 
@@ -469,7 +357,6 @@ TEST(MachineInstrExtraInfo, RemoveExtraInfo) {
   MMOs.push_back(MMO);
   MCSymbol *Sym1 = MC->createTempSymbol("pre_label", false);
   MCSymbol *Sym2 = MC->createTempSymbol("post_label", false);
-  LLVMContext Ctx;
   MDNode *MDN = MDNode::getDistinct(Ctx, None);
 
   MI->setMemRefs(*MF, MMOs);


        


More information about the llvm-commits mailing list