From 3199c4e1efe3b92e383518170cde914fd0c6792a Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Mon, 2 May 2016 23:05:48 +0000 Subject: [PATCH] Add unittest for LiveIntervalAnalysis::handleMove() This re-applies r260905. It requires LiveIntervals to not require LiveVariables which was reverted and re-applied in r267954. llvm-svn: 268329 --- llvm/unittests/MI/CMakeLists.txt | 5 + llvm/unittests/MI/LiveIntervalTest.cpp | 307 ++++++++++++++++++++++++++++++++- 2 files changed, 309 insertions(+), 3 deletions(-) diff --git a/llvm/unittests/MI/CMakeLists.txt b/llvm/unittests/MI/CMakeLists.txt index e8a7945..283d011b 100644 --- a/llvm/unittests/MI/CMakeLists.txt +++ b/llvm/unittests/MI/CMakeLists.txt @@ -1,5 +1,10 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + AsmPrinter + CodeGen + MIRParser Support + Target ) add_llvm_unittest(MITests diff --git a/llvm/unittests/MI/LiveIntervalTest.cpp b/llvm/unittests/MI/LiveIntervalTest.cpp index 534bd0d..104bd7f 100644 --- a/llvm/unittests/MI/LiveIntervalTest.cpp +++ b/llvm/unittests/MI/LiveIntervalTest.cpp @@ -1,6 +1,307 @@ #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" -// FIXME: It may be removed when practical tests came. -TEST(LiveIntervalTest, DummyStub) { - EXPECT_TRUE(true); +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(LLVMContext &Context, + legacy::PassManagerBase &PM, std::unique_ptr &MIR, + const TargetMachine &TM, StringRef MIRCode, const char *FuncName) { + SMDiagnostic Diagnostic; + std::unique_ptr MBuffer = MemoryBuffer::getMemBuffer(MIRCode); + MIR = 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(). + */ +static void testHandleMove(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); +} + +static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T) { + LLVMContext Context; + 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(Context, 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. + liveIntervalTest( +" NOOP\n" +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpRedef) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpEarlyDef) { + liveIntervalTest( +" NOOP\n" +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpEarlyRedef) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpKill) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 2, 1); + }); +} + +TEST(LiveIntervalTest, MoveUpKillFollowing) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit %0\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(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. + liveIntervalTest( +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownRedef) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownEarlyDef) { + liveIntervalTest( +" NOOP\n" +" early-clobber %0 = IMPLICIT_DEF\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownEarlyRedef) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n" +" NOOP\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownKill) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP implicit %0\n" +" NOOP\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +TEST(LiveIntervalTest, MoveDownKillFollowing) { + liveIntervalTest( +" %0 = IMPLICIT_DEF\n" +" NOOP\n" +" NOOP implicit %0\n" +" RETQ %0\n", + [](MachineFunction &MF, LiveIntervals &LIS) { + testHandleMove(MF, LIS, 1, 2); + }); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + initLLVM(); + return RUN_ALL_TESTS(); } -- 2.7.4