|  | //===- MachineInstrTest.cpp -----------------------------------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/CodeGen/MachineInstr.h" | 
|  | #include "llvm/CodeGen/MachineFunction.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/DebugInfoMetadata.h" | 
|  | #include "llvm/IR/ModuleSlotTracker.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 { | 
|  | // 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, 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; } | 
|  | }; | 
|  |  | 
|  | class BogusSubtarget : public TargetSubtargetInfo { | 
|  | public: | 
|  | BogusSubtarget(TargetMachine &TM) | 
|  | : TargetSubtargetInfo(Triple(""), "", "", {}, {}, nullptr, 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; } | 
|  |  | 
|  | private: | 
|  | BogusFrameLowering FL; | 
|  | 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 llvm::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 llvm::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(); | 
|  |  | 
|  | unsigned short NumOps = 2; | 
|  | unsigned char NumDefs = 1; | 
|  | MCOperandInfo OpInfo[] = { | 
|  | {0, 0, MCOI::OPERAND_REGISTER, 0}, | 
|  | {0, 1 << MCOI::OptionalDef, MCOI::OPERAND_REGISTER, 0}}; | 
|  | MCInstrDesc MCID = { | 
|  | 0, NumOps,  NumDefs, 0,      0, 1ULL << MCID::HasOptionalDef, | 
|  | 0, nullptr, nullptr, OpInfo, 0, nullptr}; | 
|  |  | 
|  | // Create two MIs with different virtual reg defs and the same uses. | 
|  | unsigned VirtualDef1 = -42; // The value doesn't matter, but the sign does. | 
|  | unsigned VirtualDef2 = -43; | 
|  | unsigned VirtualUse = -44; | 
|  |  | 
|  | auto MI1 = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | MI1->addOperand(*MF, MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true)); | 
|  | MI1->addOperand(*MF, MachineOperand::CreateReg(VirtualUse, /*isDef*/ false)); | 
|  |  | 
|  | auto MI2 = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | MI2->addOperand(*MF, MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true)); | 
|  | MI2->addOperand(*MF, MachineOperand::CreateReg(VirtualUse, /*isDef*/ false)); | 
|  |  | 
|  | // Check that they are identical when we ignore virtual register defs, but not | 
|  | // when we check defs. | 
|  | ASSERT_FALSE(MI1->isIdenticalTo(*MI2, MachineInstr::CheckDefs)); | 
|  | ASSERT_FALSE(MI2->isIdenticalTo(*MI1, MachineInstr::CheckDefs)); | 
|  |  | 
|  | ASSERT_TRUE(MI1->isIdenticalTo(*MI2, MachineInstr::IgnoreVRegDefs)); | 
|  | ASSERT_TRUE(MI2->isIdenticalTo(*MI1, MachineInstr::IgnoreVRegDefs)); | 
|  |  | 
|  | // Create two MIs with different virtual reg defs, and a def or use of a | 
|  | // sentinel register. | 
|  | unsigned SentinelReg = 0; | 
|  |  | 
|  | auto MI3 = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | MI3->addOperand(*MF, MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true)); | 
|  | MI3->addOperand(*MF, MachineOperand::CreateReg(SentinelReg, /*isDef*/ true)); | 
|  |  | 
|  | auto MI4 = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | MI4->addOperand(*MF, MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true)); | 
|  | MI4->addOperand(*MF, MachineOperand::CreateReg(SentinelReg, /*isDef*/ false)); | 
|  |  | 
|  | // Check that they are never identical. | 
|  | ASSERT_FALSE(MI3->isIdenticalTo(*MI4, MachineInstr::CheckDefs)); | 
|  | ASSERT_FALSE(MI4->isIdenticalTo(*MI3, MachineInstr::CheckDefs)); | 
|  |  | 
|  | ASSERT_FALSE(MI3->isIdenticalTo(*MI4, MachineInstr::IgnoreVRegDefs)); | 
|  | ASSERT_FALSE(MI4->isIdenticalTo(*MI3, MachineInstr::IgnoreVRegDefs)); | 
|  | } | 
|  |  | 
|  | // Check that MachineInstrExpressionTrait::isEqual is symmetric and in sync with | 
|  | // MachineInstrExpressionTrait::getHashValue | 
|  | void checkHashAndIsEqualMatch(MachineInstr *MI1, MachineInstr *MI2) { | 
|  | bool IsEqual1 = MachineInstrExpressionTrait::isEqual(MI1, MI2); | 
|  | bool IsEqual2 = MachineInstrExpressionTrait::isEqual(MI2, MI1); | 
|  |  | 
|  | ASSERT_EQ(IsEqual1, IsEqual2); | 
|  |  | 
|  | auto Hash1 = MachineInstrExpressionTrait::getHashValue(MI1); | 
|  | auto Hash2 = MachineInstrExpressionTrait::getHashValue(MI2); | 
|  |  | 
|  | ASSERT_EQ(IsEqual1, Hash1 == Hash2); | 
|  | } | 
|  |  | 
|  | // This test makes sure that MachineInstrExpressionTraits::isEqual is in sync | 
|  | // with MachineInstrExpressionTraits::getHashValue. | 
|  | TEST(MachineInstrExpressionTraitTest, IsEqualAgreesWithGetHashValue) { | 
|  | auto MF = createMachineFunction(); | 
|  |  | 
|  | unsigned short NumOps = 2; | 
|  | unsigned char NumDefs = 1; | 
|  | MCOperandInfo OpInfo[] = { | 
|  | {0, 0, MCOI::OPERAND_REGISTER, 0}, | 
|  | {0, 1 << MCOI::OptionalDef, MCOI::OPERAND_REGISTER, 0}}; | 
|  | MCInstrDesc MCID = { | 
|  | 0, NumOps,  NumDefs, 0,      0, 1ULL << MCID::HasOptionalDef, | 
|  | 0, nullptr, nullptr, OpInfo, 0, nullptr}; | 
|  |  | 
|  | // Define a series of instructions with different kinds of operands and make | 
|  | // sure that the hash function is consistent with isEqual for various | 
|  | // combinations of them. | 
|  | unsigned VirtualDef1 = -42; | 
|  | unsigned VirtualDef2 = -43; | 
|  | unsigned VirtualReg = -44; | 
|  | unsigned SentinelReg = 0; | 
|  | unsigned PhysicalReg = 45; | 
|  |  | 
|  | auto VD1VU = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | VD1VU->addOperand(*MF, | 
|  | MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true)); | 
|  | VD1VU->addOperand(*MF, | 
|  | MachineOperand::CreateReg(VirtualReg, /*isDef*/ false)); | 
|  |  | 
|  | auto VD2VU = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | VD2VU->addOperand(*MF, | 
|  | MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true)); | 
|  | VD2VU->addOperand(*MF, | 
|  | MachineOperand::CreateReg(VirtualReg, /*isDef*/ false)); | 
|  |  | 
|  | auto VD1SU = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | VD1SU->addOperand(*MF, | 
|  | MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true)); | 
|  | VD1SU->addOperand(*MF, | 
|  | MachineOperand::CreateReg(SentinelReg, /*isDef*/ false)); | 
|  |  | 
|  | auto VD1SD = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | VD1SD->addOperand(*MF, | 
|  | MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true)); | 
|  | VD1SD->addOperand(*MF, | 
|  | MachineOperand::CreateReg(SentinelReg, /*isDef*/ true)); | 
|  |  | 
|  | auto VD2PU = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | VD2PU->addOperand(*MF, | 
|  | MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true)); | 
|  | VD2PU->addOperand(*MF, | 
|  | MachineOperand::CreateReg(PhysicalReg, /*isDef*/ false)); | 
|  |  | 
|  | auto VD2PD = MF->CreateMachineInstr(MCID, DebugLoc()); | 
|  | VD2PD->addOperand(*MF, | 
|  | MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true)); | 
|  | VD2PD->addOperand(*MF, | 
|  | MachineOperand::CreateReg(PhysicalReg, /*isDef*/ true)); | 
|  |  | 
|  | checkHashAndIsEqualMatch(VD1VU, VD2VU); | 
|  | checkHashAndIsEqualMatch(VD1VU, VD1SU); | 
|  | checkHashAndIsEqualMatch(VD1VU, VD1SD); | 
|  | checkHashAndIsEqualMatch(VD1VU, VD2PU); | 
|  | checkHashAndIsEqualMatch(VD1VU, VD2PD); | 
|  |  | 
|  | checkHashAndIsEqualMatch(VD2VU, VD1SU); | 
|  | checkHashAndIsEqualMatch(VD2VU, VD1SD); | 
|  | checkHashAndIsEqualMatch(VD2VU, VD2PU); | 
|  | checkHashAndIsEqualMatch(VD2VU, VD2PD); | 
|  |  | 
|  | checkHashAndIsEqualMatch(VD1SU, VD1SD); | 
|  | checkHashAndIsEqualMatch(VD1SU, VD2PU); | 
|  | checkHashAndIsEqualMatch(VD1SU, VD2PD); | 
|  |  | 
|  | checkHashAndIsEqualMatch(VD1SD, VD2PU); | 
|  | checkHashAndIsEqualMatch(VD1SD, VD2PD); | 
|  |  | 
|  | checkHashAndIsEqualMatch(VD2PU, VD2PD); | 
|  | } | 
|  |  | 
|  | TEST(MachineInstrPrintingTest, DebugLocPrinting) { | 
|  | auto MF = createMachineFunction(); | 
|  |  | 
|  | 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, false, false, 0, nullptr, 0, 0, 0, | 
|  | DINode::FlagZero, false, nullptr); | 
|  | DILocation *DIL = DILocation::get(Ctx, 1, 5, DIS); | 
|  | DebugLoc DL(DIL); | 
|  | MachineInstr *MI = MF->CreateMachineInstr(MCID, DL); | 
|  | MI->addOperand(*MF, MachineOperand::CreateReg(0, /*isDef*/ true)); | 
|  |  | 
|  | std::string str; | 
|  | raw_string_ostream OS(str); | 
|  | MI->print(OS); | 
|  | ASSERT_TRUE( | 
|  | StringRef(OS.str()).startswith("$noreg = UNKNOWN debug-location ")); | 
|  | ASSERT_TRUE( | 
|  | StringRef(OS.str()).endswith("filename:1:5")); | 
|  | } | 
|  |  | 
|  | } // end namespace |