diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h --- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h +++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h @@ -704,6 +704,7 @@ std::vector CallSitesInfo; std::vector DebugValueSubstitutions; MachineJumpTable JumpTableInfo; + std::vector MachineMetadataNodes; BlockStringValue Body; }; @@ -738,6 +739,9 @@ YamlIO.mapOptional("machineFunctionInfo", MF.MachineFuncInfo); if (!YamlIO.outputting() || !MF.JumpTableInfo.Entries.empty()) YamlIO.mapOptional("jumpTable", MF.JumpTableInfo, MachineJumpTable()); + if (!YamlIO.outputting() || !MF.MachineMetadataNodes.empty()) + YamlIO.mapOptional("machineMetadataNodes", MF.MachineMetadataNodes, + std::vector()); YamlIO.mapOptional("body", MF.Body, BlockStringValue()); } }; diff --git a/llvm/include/llvm/CodeGen/MachineModuleSlotTracker.h b/llvm/include/llvm/CodeGen/MachineModuleSlotTracker.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/CodeGen/MachineModuleSlotTracker.h @@ -0,0 +1,45 @@ +//===-- llvm/CodeGen/MachineModuleInfo.h ------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_MACHINEMODULESLOTTRACKER_H +#define LLVM_CODEGEN_MACHINEMODULESLOTTRACKER_H + +#include "llvm/IR/ModuleSlotTracker.h" + +namespace llvm { + +class AbstractSlotTrackerStorage; +class Function; +class MachineModuleInfo; +class MachineFunction; +class Module; + +class MachineModuleSlotTracker : public ModuleSlotTracker { + const Function &TheFunction; + const MachineModuleInfo &TheMMI; + unsigned MDNStartSlot, MDNEndSlot; + + void processMachineFunctionMetadata(AbstractSlotTrackerStorage *AST, + const MachineFunction &MF); + void processMachineModule(AbstractSlotTrackerStorage *AST, const Module *M, + bool ShouldInitializeAllMetadata); + void processMachineFunction(AbstractSlotTrackerStorage *AST, + const Function *F, + bool ShouldInitializeAllMetadata); + +public: + MachineModuleSlotTracker(const MachineFunction *MF, + bool ShouldInitializeAllMetadata = true); + ~MachineModuleSlotTracker(); + + void collectMachineMDNodes(MachineMDNodeListType &L) const; +}; + +} // namespace llvm + +#endif // LLVM_CODEGEN_MACHINEMODULESLOTTRACKER_H diff --git a/llvm/include/llvm/IR/ModuleSlotTracker.h b/llvm/include/llvm/IR/ModuleSlotTracker.h --- a/llvm/include/llvm/IR/ModuleSlotTracker.h +++ b/llvm/include/llvm/IR/ModuleSlotTracker.h @@ -9,7 +9,10 @@ #ifndef LLVM_IR_MODULESLOTTRACKER_H #define LLVM_IR_MODULESLOTTRACKER_H +#include #include +#include +#include namespace llvm { @@ -17,6 +20,18 @@ class Function; class SlotTracker; class Value; +class MDNode; + +/// Abstract interface of slot tracker storage. +class AbstractSlotTrackerStorage { +public: + virtual ~AbstractSlotTrackerStorage(); + + virtual unsigned getNextMetadataSlot() = 0; + + virtual void createMetadataSlot(const MDNode *) = 0; + virtual int getMetadataSlot(const MDNode *) = 0; +}; /// Manage lifetime of a slot tracker for printing IR. /// @@ -36,6 +51,11 @@ const Function *F = nullptr; SlotTracker *Machine = nullptr; + std::function + processModuleHookFn; + std::function + processFunctionHookFn; + public: /// Wrap a preinitialized SlotTracker. ModuleSlotTracker(SlotTracker &Machine, const Module *M, @@ -52,7 +72,7 @@ bool ShouldInitializeAllMetadata = true); /// Destructor to clean up storage. - ~ModuleSlotTracker(); + virtual ~ModuleSlotTracker(); /// Lazily creates a slot tracker. SlotTracker *getMachine(); @@ -72,6 +92,16 @@ /// this method. /// Return -1 if the value is not in the function's SlotTracker. int getLocalSlot(const Value *V); + + void setProcessHook( + std::function); + void setProcessHook(std::function); + + using MachineMDNodeListType = + std::vector>; + + void collectMDNodes(MachineMDNodeListType &L, unsigned LB, unsigned UB) const; }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -91,6 +91,7 @@ MachineLoopUtils.cpp MachineModuleInfo.cpp MachineModuleInfoImpls.cpp + MachineModuleSlotTracker.cpp MachineOperand.cpp MachineOptimizationRemarkEmitter.cpp MachineOutliner.cpp diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp --- a/llvm/lib/CodeGen/MIRPrinter.cpp +++ b/llvm/lib/CodeGen/MIRPrinter.cpp @@ -29,6 +29,7 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/MachineModuleSlotTracker.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" @@ -135,6 +136,9 @@ void convertCallSiteObjects(yaml::MachineFunction &YMF, const MachineFunction &MF, ModuleSlotTracker &MST); + void convertMachineMetadataNodes(yaml::MachineFunction &YMF, + const MachineFunction &MF, + MachineModuleSlotTracker &MST); private: void initRegisterMaskIds(const MachineFunction &MF); @@ -215,7 +219,7 @@ MachineFunctionProperties::Property::FailedISel); convert(YamlMF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo()); - ModuleSlotTracker MST(MF.getFunction().getParent()); + MachineModuleSlotTracker MST(&MF); MST.incorporateFunction(MF.getFunction()); convert(MST, YamlMF.FrameInfo, MF.getFrameInfo()); convertStackObjects(YamlMF, MF, MST); @@ -243,6 +247,10 @@ IsNewlineNeeded = true; } StrOS.flush(); + // Convert machine metadata collected during the print of the machine + // function. + convertMachineMetadataNodes(YamlMF, MF, MST); + yaml::Output Out(OS); if (!SimplifyMIR) Out.setWriteDefaultValues(true); @@ -525,6 +533,19 @@ }); } +void MIRPrinter::convertMachineMetadataNodes(yaml::MachineFunction &YMF, + const MachineFunction &MF, + MachineModuleSlotTracker &MST) { + MachineModuleSlotTracker::MachineMDNodeListType MDList; + MST.collectMachineMDNodes(MDList); + for (auto &MD : MDList) { + std::string NS; + raw_string_ostream StrOS(NS); + MD.second->print(StrOS, MST, MF.getFunction().getParent()); + YMF.MachineMetadataNodes.push_back(StrOS.str()); + } +} + void MIRPrinter::convert(yaml::MachineFunction &MF, const MachineConstantPool &ConstantPool) { unsigned ID = 0; diff --git a/llvm/lib/CodeGen/MachineModuleSlotTracker.cpp b/llvm/lib/CodeGen/MachineModuleSlotTracker.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/MachineModuleSlotTracker.cpp @@ -0,0 +1,81 @@ +//===-- llvm/CodeGen/MachineModuleInfo.cpp ----------------------*- C++ -*-===// +// +// 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/MachineModuleSlotTracker.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" + +using namespace llvm; + +void MachineModuleSlotTracker::processMachineFunctionMetadata( + AbstractSlotTrackerStorage *AST, const MachineFunction &MF) { + // Create metadata created within the backend. + for (const MachineBasicBlock &MBB : MF) + for (const MachineInstr &MI : MBB.instrs()) + for (const MachineMemOperand *MMO : MI.memoperands()) { + AAMDNodes AAInfo = MMO->getAAInfo(); + if (AAInfo.TBAA) + AST->createMetadataSlot(AAInfo.TBAA); + if (AAInfo.TBAAStruct) + AST->createMetadataSlot(AAInfo.TBAAStruct); + if (AAInfo.Scope) + AST->createMetadataSlot(AAInfo.Scope); + if (AAInfo.NoAlias) + AST->createMetadataSlot(AAInfo.NoAlias); + } +} + +void MachineModuleSlotTracker::processMachineModule( + AbstractSlotTrackerStorage *AST, const Module *M, + bool ShouldInitializeAllMetadata) { + if (ShouldInitializeAllMetadata) { + for (const Function &F : *M) { + if (&F != &TheFunction) + continue; + MDNStartSlot = AST->getNextMetadataSlot(); + if (auto MF = TheMMI.getMachineFunction(F)) + processMachineFunctionMetadata(AST, *MF); + MDNEndSlot = AST->getNextMetadataSlot(); + break; + } + } +} + +void MachineModuleSlotTracker::processMachineFunction( + AbstractSlotTrackerStorage *AST, const Function *F, + bool ShouldInitializeAllMetadata) { + if (!ShouldInitializeAllMetadata && F == &TheFunction) { + MDNStartSlot = AST->getNextMetadataSlot(); + if (auto MF = TheMMI.getMachineFunction(*F)) + processMachineFunctionMetadata(AST, *MF); + MDNEndSlot = AST->getNextMetadataSlot(); + } +} + +void MachineModuleSlotTracker::collectMachineMDNodes( + MachineMDNodeListType &L) const { + collectMDNodes(L, MDNStartSlot, MDNEndSlot); +} + +MachineModuleSlotTracker::MachineModuleSlotTracker( + const MachineFunction *MF, bool ShouldInitializeAllMetadata) + : ModuleSlotTracker(MF->getFunction().getParent(), + ShouldInitializeAllMetadata), + TheFunction(MF->getFunction()), TheMMI(MF->getMMI()), MDNStartSlot(0), + MDNEndSlot(0) { + setProcessHook([this](AbstractSlotTrackerStorage *AST, const Module *M, + bool ShouldInitializeAllMetadata) { + this->processMachineModule(AST, M, ShouldInitializeAllMetadata); + }); + setProcessHook([this](AbstractSlotTrackerStorage *AST, const Function *F, + bool ShouldInitializeAllMetadata) { + this->processMachineFunction(AST, F, ShouldInitializeAllMetadata); + }); +} + +MachineModuleSlotTracker::~MachineModuleSlotTracker() = default; diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -713,6 +713,8 @@ OS << '>'; } +AbstractSlotTrackerStorage::~AbstractSlotTrackerStorage() {} + namespace llvm { //===----------------------------------------------------------------------===// @@ -720,7 +722,7 @@ //===----------------------------------------------------------------------===// /// This class provides computation of slot numbers for LLVM Assembly writing. /// -class SlotTracker { +class SlotTracker : public AbstractSlotTrackerStorage { public: /// ValueMap - A mapping of Values to slot numbers. using ValueMap = DenseMap; @@ -734,6 +736,11 @@ bool FunctionProcessed = false; bool ShouldInitializeAllMetadata; + std::function + processModuleHookFn; + std::function + processFunctionHookFn; + /// The summary index for which we are holding slot numbers. const ModuleSummaryIndex *TheIndex = nullptr; @@ -788,11 +795,22 @@ SlotTracker(const SlotTracker &) = delete; SlotTracker &operator=(const SlotTracker &) = delete; + ~SlotTracker() = default; + + void setProcessHook( + std::function); + void setProcessHook(std::function); + + unsigned getNextMetadataSlot() override { return mdnNext; } + + void createMetadataSlot(const MDNode *N) override; + /// Return the slot number of the specified value in it's type /// plane. If something is not in the SlotTracker, return -1. int getLocalSlot(const Value *V); int getGlobalSlot(const GlobalValue *V); - int getMetadataSlot(const MDNode *N); + int getMetadataSlot(const MDNode *N) override; int getAttributeGroupSlot(AttributeSet AS); int getModulePathSlot(StringRef Path); int getGUIDSlot(GlobalValue::GUID GUID); @@ -893,6 +911,10 @@ MachineStorage = std::make_unique(M, ShouldInitializeAllMetadata); Machine = MachineStorage.get(); + if (processModuleHookFn) + Machine->setProcessHook(processModuleHookFn); + if (processFunctionHookFn) + Machine->setProcessHook(processFunctionHookFn); return Machine; } @@ -915,6 +937,18 @@ return Machine->getLocalSlot(V); } +void ModuleSlotTracker::setProcessHook( + std::function + Fn) { + processModuleHookFn = Fn; +} + +void ModuleSlotTracker::setProcessHook( + std::function + Fn) { + processFunctionHookFn = Fn; +} + static SlotTracker *createSlotTracker(const Value *V) { if (const Argument *FA = dyn_cast(V)) return new SlotTracker(FA->getParent()); @@ -1025,6 +1059,9 @@ CreateAttributeSetSlot(FnAttrs); } + if (processModuleHookFn) + processModuleHookFn(this, TheModule, ShouldInitializeAllMetadata); + ST_DEBUG("end processModule!\n"); } @@ -1065,6 +1102,9 @@ } } + if (processFunctionHookFn) + processFunctionHookFn(this, TheFunction, ShouldInitializeAllMetadata); + FunctionProcessed = true; ST_DEBUG("end processFunction!\n"); @@ -1155,6 +1195,23 @@ return MI == mMap.end() ? -1 : (int)MI->second; } +void SlotTracker::setProcessHook( + std::function + Fn) { + processModuleHookFn = Fn; +} + +void SlotTracker::setProcessHook( + std::function + Fn) { + processFunctionHookFn = Fn; +} + +/// getMetadataSlot - Get the slot number of a MDNode. +void SlotTracker::createMetadataSlot(const MDNode *N) { + CreateMetadataSlot(N); +} + /// getMetadataSlot - Get the slot number of a MDNode. int SlotTracker::getMetadataSlot(const MDNode *N) { // Check for uninitialized state and do lazy initialization. @@ -4767,6 +4824,17 @@ W.printModuleSummaryIndex(); } +void ModuleSlotTracker::collectMDNodes(MachineMDNodeListType &L, unsigned LB, + unsigned UB) const { + SlotTracker *ST = MachineStorage.get(); + if (!ST) + return; + + for (auto &I : llvm::make_range(ST->mdn_begin(), ST->mdn_end())) + if (I.second >= LB && I.second < UB) + L.push_back(std::make_pair(I.second, I.first)); +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) // Value::dump - allow easy printing of Values from the debugger. LLVM_DUMP_METHOD 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 @@ -5,6 +5,7 @@ AsmPrinter CodeGen Core + FileCheck MC MIRParser Passes @@ -30,6 +31,7 @@ TypeTraitsTest.cpp TargetOptionsTest.cpp TestAsmPrinter.cpp + MachineMetadata.cpp ) add_subdirectory(GlobalISel) diff --git a/llvm/unittests/CodeGen/MachineMetadata.cpp b/llvm/unittests/CodeGen/MachineMetadata.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/CodeGen/MachineMetadata.cpp @@ -0,0 +1,482 @@ +//===- MachineInstrBundleIteratorTest.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/MIRParser/MIRParser.h" +#include "llvm/CodeGen/MIRPrinter.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineModuleSlotTracker.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/CodeGen/TargetLowering.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/FileCheck/FileCheck.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/ModuleSlotTracker.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "gtest/gtest.h" + +using namespace llvm; + +class MachineMetadataTest : public testing::Test { +public: + MachineMetadataTest() {} + +protected: + LLVMContext Context; + std::unique_ptr M; + std::unique_ptr MIR; + + static void SetUpTestCase() { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + } + + void SetUp() override { M = std::make_unique("Dummy", Context); } + + void addHooks(ModuleSlotTracker &MST, const MachineOperand &MO) { + // Setup hooks to assign slot numbers for the specified machine metadata. + MST.setProcessHook([&MO](AbstractSlotTrackerStorage *AST, const Module *M, + bool ShouldInitializeAllMetadata) { + if (ShouldInitializeAllMetadata) { + if (MO.isMetadata()) + AST->createMetadataSlot(MO.getMetadata()); + } + }); + MST.setProcessHook([&MO](AbstractSlotTrackerStorage *AST, const Function *F, + bool ShouldInitializeAllMetadata) { + if (!ShouldInitializeAllMetadata) { + if (MO.isMetadata()) + AST->createMetadataSlot(MO.getMetadata()); + } + }); + } + + std::unique_ptr + createTargetMachine(std::string TT, StringRef CPU, StringRef FS) { + std::string Error; + const Target *T = TargetRegistry::lookupTarget(TT, Error); + if (!T) + return nullptr; + TargetOptions Options; + return std::unique_ptr(static_cast( + T->createTargetMachine(TT, CPU, FS, Options, None, None))); + } + + std::unique_ptr parseMIR(const TargetMachine &TM, StringRef MIRCode, + const char *FnName, MachineModuleInfo &MMI) { + SMDiagnostic Diagnostic; + std::unique_ptr MBuffer = MemoryBuffer::getMemBuffer(MIRCode); + MIR = createMIRParser(std::move(MBuffer), Context); + if (!MIR) + return nullptr; + + std::unique_ptr Mod = MIR->parseIRModule(); + if (!Mod) + return nullptr; + + Mod->setDataLayout(TM.createDataLayout()); + + if (MIR->parseMachineFunctions(*Mod, MMI)) { + M.reset(); + return nullptr; + } + + return Mod; + } +}; + +// Helper to dump the printer output into a string. +static std::string print(std::function PrintFn) { + std::string Str; + raw_string_ostream OS(Str); + PrintFn(OS); + OS.flush(); + return Str; +} + +TEST_F(MachineMetadataTest, TrivialHook) { + // Verify that post-process hook is invoked to assign slot numbers for + // machine metadata. + ASSERT_TRUE(M); + + // Create a MachineOperand with a metadata and print it. + Metadata *MDS = MDString::get(Context, "foo"); + MDNode *Node = MDNode::get(Context, MDS); + MachineOperand MO = MachineOperand::CreateMetadata(Node); + + // Checking some preconditions on the newly created + // MachineOperand. + ASSERT_TRUE(MO.isMetadata()); + ASSERT_TRUE(MO.getMetadata() == Node); + + ModuleSlotTracker MST(M.get()); + addHooks(MST, MO); + + // Print a MachineOperand containing a metadata node. + EXPECT_EQ("!0", print([&](raw_ostream &OS) { + MO.print(OS, MST, LLT{}, /*OpIdx*/ ~0U, /*PrintDef=*/false, + /*IsStandalone=*/false, + /*ShouldPrintRegisterTies=*/false, /*TiedOperandIdx=*/0, + /*TRI=*/nullptr, + /*IntrinsicInfo=*/nullptr); + })); + // Print the definition of that metadata node. + EXPECT_EQ("!0 = !{!\"foo\"}", + print([&](raw_ostream &OS) { Node->print(OS, MST); })); +} + +TEST_F(MachineMetadataTest, BasicHook) { + // Verify that post-process hook is invoked to assign slot numbers for + // machine metadata. When both LLVM IR and machine IR contain metadata, + // ensure that machine metadata is always assigned after LLVM IR. + ASSERT_TRUE(M); + + // Create a MachineOperand with a metadata and print it. + Metadata *MachineMDS = MDString::get(Context, "foo"); + MDNode *MachineNode = MDNode::get(Context, MachineMDS); + MachineOperand MO = MachineOperand::CreateMetadata(MachineNode); + + // Checking some preconditions on the newly created + // MachineOperand. + ASSERT_TRUE(MO.isMetadata()); + ASSERT_TRUE(MO.getMetadata() == MachineNode); + + // Create metadata in LLVM IR. + NamedMDNode *MD = M->getOrInsertNamedMetadata("namedmd"); + Metadata *MDS = MDString::get(Context, "bar"); + MDNode *Node = MDNode::get(Context, MDS); + MD->addOperand(Node); + + ModuleSlotTracker MST(M.get()); + addHooks(MST, MO); + + // Print a MachineOperand containing a metadata node. + EXPECT_EQ("!1", print([&](raw_ostream &OS) { + MO.print(OS, MST, LLT{}, /*OpIdx*/ ~0U, /*PrintDef=*/false, + /*IsStandalone=*/false, + /*ShouldPrintRegisterTies=*/false, /*TiedOperandIdx=*/0, + /*TRI=*/nullptr, + /*IntrinsicInfo=*/nullptr); + })); + // Print the definition of these unnamed metadata nodes. + EXPECT_EQ("!0 = !{!\"bar\"}", + print([&](raw_ostream &OS) { Node->print(OS, MST); })); + EXPECT_EQ("!1 = !{!\"foo\"}", + print([&](raw_ostream &OS) { MachineNode->print(OS, MST); })); +} + +static bool CheckOutput(std::string CheckString, std::string Output) { + auto CheckBuffer = MemoryBuffer::getMemBuffer(CheckString, ""); + auto OutputBuffer = MemoryBuffer::getMemBuffer(Output, "Output", false); + + SmallString<4096> CheckFileBuffer; + FileCheckRequest Req; + FileCheck FC(Req); + StringRef CheckFileText = + FC.CanonicalizeFile(*CheckBuffer.get(), CheckFileBuffer); + + SourceMgr SM; + SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(CheckFileText, "CheckFile"), + SMLoc()); + Regex PrefixRE = FC.buildCheckPrefixRegex(); + if (FC.readCheckFile(SM, CheckFileText, PrefixRE)) + return false; + + auto OutBuffer = OutputBuffer->getBuffer(); + SM.AddNewSourceBuffer(std::move(OutputBuffer), SMLoc()); + return FC.checkInput(SM, OutBuffer); +} + +TEST_F(MachineMetadataTest, MMSlotTrackerAArch64) { + auto TM = createTargetMachine(Triple::normalize("aarch64--"), "", ""); + if (!TM) + GTEST_SKIP(); + + StringRef MIRString = R"MIR( +--- | + define i32 @test0(i32* %p) { + %r = load i32, i32* %p, align 4 + ret i32 %r + } +... +--- +name: test0 +liveins: + - { reg: '$x0', virtual-reg: '%0' } +body: | + bb.0 (%ir-block.0): + liveins: $x0 + + %0:gpr64common = COPY $x0 + %1:gpr32 = LDRWui %0, 0 :: (load 4 from %ir.p) +... +)MIR"; + + MachineModuleInfo MMI(TM.get()); + M = parseMIR(*TM, MIRString, "test0", MMI); + ASSERT_TRUE(M); + + auto MF = MMI.getMachineFunction(*M->getFunction("test0")); + auto MBB = MF->getBlockNumbered(0); + + auto &MI = MBB->back(); + ASSERT_FALSE(MI.memoperands_empty()); + ASSERT_TRUE(MI.hasOneMemOperand()); + + // Create and attached scoped AA metadata on that instruction with one MMO. + MDBuilder MDB(Context); + MDNode *Domain = MDB.createAnonymousAliasScopeDomain("domain"); + MDNode *Scope0 = MDB.createAnonymousAliasScope(Domain, "scope0"); + MDNode *Scope1 = MDB.createAnonymousAliasScope(Domain, "scope1"); + MDNode *Set0 = MDNode::get(Context, {Scope0}); + MDNode *Set1 = MDNode::get(Context, {Scope1}); + + AAMDNodes AAInfo; + AAInfo.TBAA = AAInfo.TBAAStruct = nullptr; + AAInfo.Scope = Set0; + AAInfo.NoAlias = Set1; + + auto *OldMMO = MI.memoperands().front(); + auto *NewMMO = MF->getMachineMemOperand(OldMMO, AAInfo); + MI.setMemRefs(*MF, NewMMO); + + MachineModuleSlotTracker MST(MF); + // Print that MI with new machine metadata, which slot numbers should be + // assigned. + EXPECT_EQ("%1:gpr32 = LDRWui %0, 0 :: (load 4 from %ir.p, " + "!alias.scope !0, !noalias !3)", + print([&](raw_ostream &OS) { + MI.print(OS, MST, /*IsStandalone=*/false, /*SkipOpers=*/false, + /*SkipDebugLoc=*/false, /*AddNewLine=*/false); + })); + + std::vector Generated{Domain, Scope0, Scope1, Set0, Set1}; + // Examine machine metadata collected. They should match ones + // afore-generated. + std::vector Collected; + MachineModuleSlotTracker::MachineMDNodeListType MDList; + MST.collectMachineMDNodes(MDList); + for (auto &MD : MDList) + Collected.push_back(MD.second); + + std::sort(Generated.begin(), Generated.end()); + std::sort(Collected.begin(), Collected.end()); + EXPECT_EQ(Collected, Generated); + + // FileCheck the output from MIR printer. + std::string Output = print([&](raw_ostream &OS) { printMIR(OS, *MF); }); + std::string CheckString = R"( +CHECK: machineMetadataNodes: +CHECK-DAG: ![[MMDOMAIN:[0-9]+]] = distinct !{!{{[0-9]+}}, !"domain"} +CHECK-DAG: ![[MMSCOPE0:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope0"} +CHECK-DAG: ![[MMSCOPE1:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope1"} +CHECK-DAG: ![[MMSET0:[0-9]+]] = !{![[MMSCOPE0]]} +CHECK-DAG: ![[MMSET1:[0-9]+]] = !{![[MMSCOPE1]]} +CHECK: body: +CHECK: %1:gpr32 = LDRWui %0, 0 :: (load 4 from %ir.p, !alias.scope ![[MMSET0]], !noalias ![[MMSET1]]) +)"; + EXPECT_TRUE(CheckOutput(CheckString, Output)); +} + +TEST_F(MachineMetadataTest, MMSlotTrackerX64) { + auto TM = createTargetMachine(Triple::normalize("x86_64--"), "", ""); + if (!TM) + GTEST_SKIP(); + + StringRef MIRString = R"MIR( +--- | + define i32 @test0(i32* %p) { + %r = load i32, i32* %p, align 4 + ret i32 %r + } +... +--- +name: test0 +liveins: + - { reg: '$rdi', virtual-reg: '%0' } +body: | + bb.0 (%ir-block.0): + liveins: $rdi + + %0:gr64 = COPY $rdi + %1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load 4 from %ir.p) +... +)MIR"; + + MachineModuleInfo MMI(TM.get()); + M = parseMIR(*TM, MIRString, "test0", MMI); + ASSERT_TRUE(M); + + auto MF = MMI.getMachineFunction(*M->getFunction("test0")); + auto MBB = MF->getBlockNumbered(0); + + auto &MI = MBB->back(); + ASSERT_FALSE(MI.memoperands_empty()); + ASSERT_TRUE(MI.hasOneMemOperand()); + + // Create and attached scoped AA metadata on that instruction with one MMO. + MDBuilder MDB(Context); + MDNode *Domain = MDB.createAnonymousAliasScopeDomain("domain"); + MDNode *Scope0 = MDB.createAnonymousAliasScope(Domain, "scope0"); + MDNode *Scope1 = MDB.createAnonymousAliasScope(Domain, "scope1"); + MDNode *Set0 = MDNode::get(Context, {Scope0}); + MDNode *Set1 = MDNode::get(Context, {Scope1}); + + AAMDNodes AAInfo; + AAInfo.TBAA = AAInfo.TBAAStruct = nullptr; + AAInfo.Scope = Set0; + AAInfo.NoAlias = Set1; + + auto *OldMMO = MI.memoperands().front(); + auto *NewMMO = MF->getMachineMemOperand(OldMMO, AAInfo); + MI.setMemRefs(*MF, NewMMO); + + MachineModuleSlotTracker MST(MF); + // Print that MI with new machine metadata, which slot numbers should be + // assigned. + EXPECT_EQ("%1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load 4 from %ir.p, " + "!alias.scope !0, !noalias !3)", + print([&](raw_ostream &OS) { + MI.print(OS, MST, /*IsStandalone=*/false, /*SkipOpers=*/false, + /*SkipDebugLoc=*/false, /*AddNewLine=*/false); + })); + + std::vector Generated{Domain, Scope0, Scope1, Set0, Set1}; + // Examine machine metadata collected. They should match ones + // afore-generated. + std::vector Collected; + MachineModuleSlotTracker::MachineMDNodeListType MDList; + MST.collectMachineMDNodes(MDList); + for (auto &MD : MDList) + Collected.push_back(MD.second); + + std::sort(Generated.begin(), Generated.end()); + std::sort(Collected.begin(), Collected.end()); + EXPECT_EQ(Collected, Generated); + + // FileCheck the output from MIR printer. + std::string Output = print([&](raw_ostream &OS) { printMIR(OS, *MF); }); + std::string CheckString = R"( +CHECK: machineMetadataNodes: +CHECK-DAG: ![[MMDOMAIN:[0-9]+]] = distinct !{!{{[0-9]+}}, !"domain"} +CHECK-DAG: ![[MMSCOPE0:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope0"} +CHECK-DAG: ![[MMSCOPE1:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope1"} +CHECK-DAG: ![[MMSET0:[0-9]+]] = !{![[MMSCOPE0]]} +CHECK-DAG: ![[MMSET1:[0-9]+]] = !{![[MMSCOPE1]]} +CHECK: body: +CHECK: %1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load 4 from %ir.p, !alias.scope ![[MMSET0]], !noalias ![[MMSET1]]) +)"; + EXPECT_TRUE(CheckOutput(CheckString, Output)); +} + +TEST_F(MachineMetadataTest, MMSlotTrackerAMDGPU) { + auto TM = createTargetMachine(Triple::normalize("amdgcn-amd-amdhsa"), + "gfx1010", ""); + if (!TM) + GTEST_SKIP(); + + StringRef MIRString = R"MIR( +--- | + define i32 @test0(i32* %p) { + %r = load i32, i32* %p, align 4 + ret i32 %r + } +... +--- +name: test0 +liveins: + - { reg: '$vgpr0', virtual-reg: '%0' } + - { reg: '$vgpr1', virtual-reg: '%1' } + - { reg: '$sgpr30_sgpr31', virtual-reg: '%2' } +body: | + bb.0 (%ir-block.0): + liveins: $vgpr0, $vgpr1, $sgpr30_sgpr31 + + %2:sreg_64 = COPY $sgpr30_sgpr31 + %1:vgpr_32 = COPY $vgpr1 + %0:vgpr_32 = COPY $vgpr0 + %8:vreg_64 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1 + %6:vreg_64 = COPY %8 + %5:vgpr_32 = FLAT_LOAD_DWORD killed %6, 0, 0, implicit $exec, implicit $flat_scr :: (load 4 from %ir.p) +... +)MIR"; + + MachineModuleInfo MMI(TM.get()); + M = parseMIR(*TM, MIRString, "test0", MMI); + ASSERT_TRUE(M); + + auto MF = MMI.getMachineFunction(*M->getFunction("test0")); + auto MBB = MF->getBlockNumbered(0); + + auto &MI = MBB->back(); + ASSERT_FALSE(MI.memoperands_empty()); + ASSERT_TRUE(MI.hasOneMemOperand()); + + // Create and attached scoped AA metadata on that instruction with one MMO. + MDBuilder MDB(Context); + MDNode *Domain = MDB.createAnonymousAliasScopeDomain("domain"); + MDNode *Scope0 = MDB.createAnonymousAliasScope(Domain, "scope0"); + MDNode *Scope1 = MDB.createAnonymousAliasScope(Domain, "scope1"); + MDNode *Set0 = MDNode::get(Context, {Scope0}); + MDNode *Set1 = MDNode::get(Context, {Scope1}); + + AAMDNodes AAInfo; + AAInfo.TBAA = AAInfo.TBAAStruct = nullptr; + AAInfo.Scope = Set0; + AAInfo.NoAlias = Set1; + + auto *OldMMO = MI.memoperands().front(); + auto *NewMMO = MF->getMachineMemOperand(OldMMO, AAInfo); + MI.setMemRefs(*MF, NewMMO); + + MachineModuleSlotTracker MST(MF); + // Print that MI with new machine metadata, which slot numbers should be + // assigned. + EXPECT_EQ( + "%5:vgpr_32 = FLAT_LOAD_DWORD killed %4, 0, 0, implicit $exec, implicit " + "$flat_scr :: (load 4 from %ir.p, !alias.scope !0, !noalias !3)", + print([&](raw_ostream &OS) { + MI.print(OS, MST, /*IsStandalone=*/false, /*SkipOpers=*/false, + /*SkipDebugLoc=*/false, /*AddNewLine=*/false); + })); + + std::vector Generated{Domain, Scope0, Scope1, Set0, Set1}; + // Examine machine metadata collected. They should match ones + // afore-generated. + std::vector Collected; + MachineModuleSlotTracker::MachineMDNodeListType MDList; + MST.collectMachineMDNodes(MDList); + for (auto &MD : MDList) + Collected.push_back(MD.second); + + std::sort(Generated.begin(), Generated.end()); + std::sort(Collected.begin(), Collected.end()); + EXPECT_EQ(Collected, Generated); + + // FileCheck the output from MIR printer. + std::string Output = print([&](raw_ostream &OS) { printMIR(OS, *MF); }); + std::string CheckString = R"( +CHECK: machineMetadataNodes: +CHECK-DAG: ![[MMDOMAIN:[0-9]+]] = distinct !{!{{[0-9]+}}, !"domain"} +CHECK-DAG: ![[MMSCOPE0:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope0"} +CHECK-DAG: ![[MMSCOPE1:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope1"} +CHECK-DAG: ![[MMSET0:[0-9]+]] = !{![[MMSCOPE0]]} +CHECK-DAG: ![[MMSET1:[0-9]+]] = !{![[MMSCOPE1]]} +CHECK: body: +CHECK: %5:vgpr_32 = FLAT_LOAD_DWORD killed %4, 0, 0, implicit $exec, implicit $flat_scr :: (load 4 from %ir.p, !alias.scope ![[MMSET0]], !noalias ![[MMSET1]]) +)"; + EXPECT_TRUE(CheckOutput(CheckString, Output)); +}