diff --git a/llvm/lib/CodeGen/LexicalScopes.cpp b/llvm/lib/CodeGen/LexicalScopes.cpp --- a/llvm/lib/CodeGen/LexicalScopes.cpp +++ b/llvm/lib/CodeGen/LexicalScopes.cpp @@ -291,9 +291,15 @@ 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 &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 @@ 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 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 --- a/llvm/unittests/CodeGen/CMakeLists.txt +++ b/llvm/unittests/CodeGen/CMakeLists.txt @@ -16,6 +16,7 @@ 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 --- /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 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(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 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 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 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 --- /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 getRegMasks() const override { return None; } + ArrayRef 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 createTargetMachine() { + return std::make_unique(); +} + +std::unique_ptr 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(*F, *TM, STI, FunctionNum, MMI); +} + diff --git a/llvm/unittests/CodeGen/MachineInstrTest.cpp b/llvm/unittests/CodeGen/MachineInstrTest.cpp --- 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 getRegMasks() const override { return None; } - ArrayRef 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 createMCContext(MCAsmInfo *AsmInfo) { return std::make_unique( AsmInfo, nullptr, nullptr, nullptr, nullptr, false); } -std::unique_ptr createTargetMachine() { - return std::make_unique(); -} - -std::unique_ptr 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(*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 @@ // 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(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(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, 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(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 @@ 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, 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 @@ 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, 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 @@ 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);