From 45a7406c5e5626aa108f28c52784f05819e0ae77 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Mon, 15 Feb 2016 19:25:34 +0000 Subject: [PATCH] Add unittest for LiveIntervalAnalysis::handleMove() llvm-svn: 260905 --- unittests/CMakeLists.txt | 1 + unittests/MI/CMakeLists.txt | 12 ++ unittests/MI/LiveIntervalTest.cpp | 306 ++++++++++++++++++++++++++++++ 3 files changed, 319 insertions(+) create mode 100644 unittests/MI/CMakeLists.txt create mode 100644 unittests/MI/LiveIntervalTest.cpp diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index e5befcec6e0..48a573ac5bc 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -22,6 +22,7 @@ add_subdirectory(IR) add_subdirectory(LineEditor) add_subdirectory(Linker) add_subdirectory(MC) +add_subdirectory(MI) add_subdirectory(Option) add_subdirectory(ProfileData) add_subdirectory(Support) diff --git a/unittests/MI/CMakeLists.txt b/unittests/MI/CMakeLists.txt new file mode 100644 index 00000000000..283d011bf1d --- /dev/null +++ b/unittests/MI/CMakeLists.txt @@ -0,0 +1,12 @@ +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + AsmPrinter + CodeGen + MIRParser + Support + Target + ) + +add_llvm_unittest(MITests + LiveIntervalTest.cpp + ) diff --git a/unittests/MI/LiveIntervalTest.cpp b/unittests/MI/LiveIntervalTest.cpp new file mode 100644 index 00000000000..28bdea3ca74 --- /dev/null +++ b/unittests/MI/LiveIntervalTest.cpp @@ -0,0 +1,306 @@ +#include "gtest/gtest.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MIRParser/MIRParser.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionAnalysis.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.H" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/IR/LegacyPassManager.h" + +using namespace llvm; + +namespace llvm { + void initializeTestPassPass(PassRegistry &); +} + +namespace { + +void initLLVM() { + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + PassRegistry *Registry = PassRegistry::getPassRegistry(); + initializeCore(*Registry); + initializeCodeGen(*Registry); +} + +/// Create a TargetMachine. As we lack a dedicated always available target for +/// unittests, we go for "x86_64" which should be available in most builds. +std::unique_ptr createTargetMachine() { + Triple TargetTriple("x86_64--"); + std::string Error; + const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); + if (!T) + return nullptr; + + TargetOptions Options; + return std::unique_ptr( + T->createTargetMachine("x86_64", "", "", Options, Reloc::Default, + CodeModel::Default, CodeGenOpt::Aggressive)); +} + +std::unique_ptr parseMIR(legacy::PassManagerBase &PM, + std::unique_ptr &MIR, const TargetMachine &TM, + StringRef MIRCode, const char *FuncName) { + LLVMContext &Context = getGlobalContext(); + + SMDiagnostic Diagnostic; + std::unique_ptr MBuffer = MemoryBuffer::getMemBuffer(MIRCode); + MIR = std::move(createMIRParser(std::move(MBuffer), Context)); + if (!MIR) + return nullptr; + + std::unique_ptr M = MIR->parseLLVMModule(); + if (!M) + return nullptr; + + M->setDataLayout(TM.createDataLayout()); + + Function *F = M->getFunction(FuncName); + if (!F) + return nullptr; + + MachineModuleInfo *MMI = new MachineModuleInfo( + *TM.getMCAsmInfo(), *TM.getMCRegisterInfo(), nullptr); + PM.add(MMI); + + MachineFunctionAnalysis *MFA = new MachineFunctionAnalysis(TM, MIR.get()); + PM.add(MFA); + + return M; +} + +typedef std::function LiveIntervalTest; + +struct TestPass : public MachineFunctionPass { + static char ID; + TestPass() : MachineFunctionPass(ID) { + // We should never call this but always use PM.add(new TestPass(...)) + abort(); + } + TestPass(LiveIntervalTest T) : MachineFunctionPass(ID), T(T) { + initializeTestPassPass(*PassRegistry::getPassRegistry()); + } + + bool runOnMachineFunction(MachineFunction &MF) override { + LiveIntervals &LIS = getAnalysis(); + T(MF, LIS); + EXPECT_TRUE(MF.verify(this)); + return true; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + AU.addRequired(); + AU.addPreserved(); + MachineFunctionPass::getAnalysisUsage(AU); + } +private: + LiveIntervalTest T; +}; + +/** + * Move instruction number \p From in front of instruction number \p To and + * update affected liveness intervals with LiveIntervalAnalysis::handleMove(). + */ +void Move(MachineFunction &MF, LiveIntervals &LIS, unsigned From, unsigned To) { + MachineBasicBlock &MBB = MF.front(); + + unsigned I = 0; + MachineInstr *FromInstr = nullptr; + MachineInstr *ToInstr = nullptr; + for (MachineInstr &MI : MBB) { + if (I == From) + FromInstr = &MI; + if (I == To) + ToInstr = &MI; + ++I; + } + assert(FromInstr != nullptr && ToInstr != nullptr); + + MBB.splice(ToInstr->getIterator(), &MBB, FromInstr->getIterator()); + LIS.handleMove(FromInstr, true); +} + +void DoLiveIntervalTest(StringRef MIRFunc, LiveIntervalTest T) { + std::unique_ptr TM = createTargetMachine(); + // This test is designed for the X86 backend; stop if it is not available. + if (!TM) + return; + + legacy::PassManager PM; + + SmallString<160> S; + StringRef MIRString = (Twine( +"---\n" +"...\n" +"name: func\n" +"registers:\n" +" - { id: 0, class: gr64 }\n" +"body: |\n" +" bb.0:\n" + ) + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(S); + std::unique_ptr MIR; + std::unique_ptr M = parseMIR(PM, MIR, *TM, MIRString, "func"); + + PM.add(new TestPass(T)); + + PM.run(*M); +} + +} // End of anonymous namespace. + +char TestPass::ID = 0; +INITIALIZE_PASS(TestPass, "testpass", "testpass", false, false) + +TEST(LiveIntervalTest, MoveUpDef) { + // Value defined. + DoLiveIntervalTest( +" NOOP\n" +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpRedef) { + DoLiveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpEarlyDef) { + DoLiveIntervalTest( +" NOOP\n" +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpEarlyRedef) { + DoLiveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpKill) { + DoLiveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpKillFollowing) { + DoLiveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit %0\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 2, 1); + }); +} + +// TODO: Construct a situation where we have intervals following a hole +// while still having connected components. + +TEST(LiveIntervalTest, MoveDownDef) { + // Value defined. + DoLiveIntervalTest( +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownRedef) { + DoLiveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownEarlyDef) { + DoLiveIntervalTest( +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownEarlyRedef) { + DoLiveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownKill) { + DoLiveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP implicit %0\n" +" NOOP\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownKillFollowing) { + DoLiveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit %0\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + Move(MF, LIS, 1, 2); + }); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + initLLVM(); + return RUN_ALL_TESTS(); +}