#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/IRBuilder.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/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 "MFCommon.inc"
class LexicalScopesTest : public testing::Test {
public:
LLVMContext Ctx;
Module Mod;
std::unique_ptr<MachineFunction> MF;
DICompileUnit *OurCU;
DIFile *OurFile;
DISubprogram *OurFunc;
DILexicalBlock *OurBlock, *AnotherBlock;
DISubprogram *ToInlineFunc;
DILexicalBlock *ToInlineBlock;
DebugLoc OutermostLoc, InBlockLoc, NotNestedBlockLoc, InlinedLoc;
MachineBasicBlock *MBB1, *MBB2, *MBB3, *MBB4;
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;
DbgValueInst.Flags = 1U << MCID::Meta;
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);
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);
OutermostLoc = DILocation::get(Ctx, 3, 1, OurFunc);
InBlockLoc = DILocation::get(Ctx, 4, 1, OurBlock);
InlinedLoc = DILocation::get(Ctx, 10, 1, ToInlineFunc, InBlockLoc.get());
NotNestedBlockLoc = DILocation::get(Ctx, 4, 1, AnotherBlock);
DIB.finalize();
}
};
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);
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);
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));
}
}
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_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_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();
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());
}
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);
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);
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);
}
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);
auto &FuncRanges = FuncScope->getRanges();
ASSERT_EQ(FuncRanges.size(), 1u);
EXPECT_EQ(FuncRanges[0].first, FirstI);
EXPECT_EQ(FuncRanges[0].second, FourthI);
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);
auto &OtherBlockRanges = OtherBlockScope->getRanges();
ASSERT_EQ(OtherBlockRanges.size(), 1u);
EXPECT_EQ(OtherBlockRanges[0].first, SecondI);
EXPECT_EQ(OtherBlockRanges[0].second, ThirdI);
}
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));
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));
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_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) {
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));
}
}