[llvm] b9c05af - [MIRPrinter] Add machine metadata support.

Michael Liao via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 19 09:48:20 PDT 2021


Author: Michael Liao
Date: 2021-06-19T12:48:08-04:00
New Revision: b9c05aff205bab3f8ca639e44b825277d6cf48a9

URL: https://github.com/llvm/llvm-project/commit/b9c05aff205bab3f8ca639e44b825277d6cf48a9
DIFF: https://github.com/llvm/llvm-project/commit/b9c05aff205bab3f8ca639e44b825277d6cf48a9.diff

LOG: [MIRPrinter] Add machine metadata support.

- Distinct metadata needs generating in the codegen to attach correct
  AAInfo on the loads/stores after lowering, merging, and other relevant
  transformations.
- This patch adds 'MachhineModuleSlotTracker' to help assign slot
  numbers to these newly generated unnamed metadata nodes.
- To help 'MachhineModuleSlotTracker' track machine metadata, the
  original 'SlotTracker' is rebased from 'AbstractSlotTrackerStorage',
  which provides basic interfaces to create/retrive metadata slots. In
  addition, once LLVM IR is processsed, additional hooks are also
  introduced to help collect machine metadata and assign them slot
  numbers.
- Finally, if there is any such machine metadata, 'MIRPrinter' outputs
  an additional 'machineMetadataNodes' field containing all the
  definition of those nodes.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D103205

Added: 
    llvm/include/llvm/CodeGen/MachineModuleSlotTracker.h
    llvm/lib/CodeGen/MachineModuleSlotTracker.cpp
    llvm/unittests/MIR/CMakeLists.txt
    llvm/unittests/MIR/MachineMetadata.cpp

Modified: 
    llvm/include/llvm/CodeGen/MIRYamlMapping.h
    llvm/include/llvm/IR/ModuleSlotTracker.h
    llvm/lib/CodeGen/CMakeLists.txt
    llvm/lib/CodeGen/MIRPrinter.cpp
    llvm/lib/IR/AsmWriter.cpp
    llvm/unittests/CMakeLists.txt
    llvm/unittests/CodeGen/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
index 9d3878fe3296f..75f2ff86c29e7 100644
--- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h
@@ -705,6 +705,7 @@ struct MachineFunction {
   std::vector<CallSiteInfo> CallSitesInfo;
   std::vector<DebugValueSubstitution> DebugValueSubstitutions;
   MachineJumpTable JumpTableInfo;
+  std::vector<StringValue> MachineMetadataNodes;
   BlockStringValue Body;
 };
 
@@ -739,6 +740,9 @@ template <> struct MappingTraits<MachineFunction> {
     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<StringValue>());
     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
index 0000000000000..0bd0a31abcae3
--- /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
index 85f8ff938366c..37cfc0f07280c 100644
--- 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 <functional>
 #include <memory>
+#include <utility>
+#include <vector>
 
 namespace llvm {
 
@@ -17,6 +20,18 @@ class Module;
 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 @@ class ModuleSlotTracker {
   const Function *F = nullptr;
   SlotTracker *Machine = nullptr;
 
+  std::function<void(AbstractSlotTrackerStorage *, const Module *, bool)>
+      ProcessModuleHookFn;
+  std::function<void(AbstractSlotTrackerStorage *, const Function *, bool)>
+      ProcessFunctionHookFn;
+
 public:
   /// Wrap a preinitialized SlotTracker.
   ModuleSlotTracker(SlotTracker &Machine, const Module *M,
@@ -52,7 +72,7 @@ class ModuleSlotTracker {
                              bool ShouldInitializeAllMetadata = true);
 
   /// Destructor to clean up storage.
-  ~ModuleSlotTracker();
+  virtual ~ModuleSlotTracker();
 
   /// Lazily creates a slot tracker.
   SlotTracker *getMachine();
@@ -72,6 +92,16 @@ class ModuleSlotTracker {
   /// this method.
   /// Return -1 if the value is not in the function's SlotTracker.
   int getLocalSlot(const Value *V);
+
+  void setProcessHook(
+      std::function<void(AbstractSlotTrackerStorage *, const Module *, bool)>);
+  void setProcessHook(std::function<void(AbstractSlotTrackerStorage *,
+                                         const Function *, bool)>);
+
+  using MachineMDNodeListType =
+      std::vector<std::pair<unsigned, const MDNode *>>;
+
+  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
index f26afa7f212c8..a08af69089394 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -91,6 +91,7 @@ add_llvm_component_library(LLVMCodeGen
   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
index 71c815538a377..c7dc73191889a 100644
--- a/llvm/lib/CodeGen/MIRPrinter.cpp
+++ b/llvm/lib/CodeGen/MIRPrinter.cpp
@@ -29,13 +29,14 @@
 #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"
+#include "llvm/CodeGen/TargetFrameLowering.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
-#include "llvm/CodeGen/TargetFrameLowering.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DebugInfo.h"
@@ -135,6 +136,9 @@ class MIRPrinter {
   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 @@ void MIRPrinter::print(const MachineFunction &MF) {
       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 @@ void MIRPrinter::print(const MachineFunction &MF) {
     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::convertCallSiteObjects(yaml::MachineFunction &YMF,
              });
 }
 
+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
index 0000000000000..e4da179efcc4d
--- /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
index 2abf17f5da3c5..25034d64556e7 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -713,6 +713,8 @@ void TypePrinting::printStructBody(StructType *STy, raw_ostream &OS) {
     OS << '>';
 }
 
+AbstractSlotTrackerStorage::~AbstractSlotTrackerStorage() {}
+
 namespace llvm {
 
 //===----------------------------------------------------------------------===//
@@ -720,7 +722,7 @@ namespace llvm {
 //===----------------------------------------------------------------------===//
 /// 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<const Value *, unsigned>;
@@ -734,6 +736,11 @@ class SlotTracker {
   bool FunctionProcessed = false;
   bool ShouldInitializeAllMetadata;
 
+  std::function<void(AbstractSlotTrackerStorage *, const Module *, bool)>
+      ProcessModuleHookFn;
+  std::function<void(AbstractSlotTrackerStorage *, const Function *, bool)>
+      ProcessFunctionHookFn;
+
   /// The summary index for which we are holding slot numbers.
   const ModuleSummaryIndex *TheIndex = nullptr;
 
@@ -788,11 +795,22 @@ class SlotTracker {
   SlotTracker(const SlotTracker &) = delete;
   SlotTracker &operator=(const SlotTracker &) = delete;
 
+  ~SlotTracker() = default;
+
+  void setProcessHook(
+      std::function<void(AbstractSlotTrackerStorage *, const Module *, bool)>);
+  void setProcessHook(std::function<void(AbstractSlotTrackerStorage *,
+                                         const Function *, bool)>);
+
+  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 @@ SlotTracker *ModuleSlotTracker::getMachine() {
   MachineStorage =
       std::make_unique<SlotTracker>(M, ShouldInitializeAllMetadata);
   Machine = MachineStorage.get();
+  if (ProcessModuleHookFn)
+    Machine->setProcessHook(ProcessModuleHookFn);
+  if (ProcessFunctionHookFn)
+    Machine->setProcessHook(ProcessFunctionHookFn);
   return Machine;
 }
 
@@ -915,6 +937,18 @@ int ModuleSlotTracker::getLocalSlot(const Value *V) {
   return Machine->getLocalSlot(V);
 }
 
+void ModuleSlotTracker::setProcessHook(
+    std::function<void(AbstractSlotTrackerStorage *, const Module *, bool)>
+        Fn) {
+  ProcessModuleHookFn = Fn;
+}
+
+void ModuleSlotTracker::setProcessHook(
+    std::function<void(AbstractSlotTrackerStorage *, const Function *, bool)>
+        Fn) {
+  ProcessFunctionHookFn = Fn;
+}
+
 static SlotTracker *createSlotTracker(const Value *V) {
   if (const Argument *FA = dyn_cast<Argument>(V))
     return new SlotTracker(FA->getParent());
@@ -1025,6 +1059,9 @@ void SlotTracker::processModule() {
       CreateAttributeSetSlot(FnAttrs);
   }
 
+  if (ProcessModuleHookFn)
+    ProcessModuleHookFn(this, TheModule, ShouldInitializeAllMetadata);
+
   ST_DEBUG("end processModule!\n");
 }
 
@@ -1065,6 +1102,9 @@ void SlotTracker::processFunction() {
     }
   }
 
+  if (ProcessFunctionHookFn)
+    ProcessFunctionHookFn(this, TheFunction, ShouldInitializeAllMetadata);
+
   FunctionProcessed = true;
 
   ST_DEBUG("end processFunction!\n");
@@ -1155,6 +1195,21 @@ int SlotTracker::getGlobalSlot(const GlobalValue *V) {
   return MI == mMap.end() ? -1 : (int)MI->second;
 }
 
+void SlotTracker::setProcessHook(
+    std::function<void(AbstractSlotTrackerStorage *, const Module *, bool)>
+        Fn) {
+  ProcessModuleHookFn = Fn;
+}
+
+void SlotTracker::setProcessHook(
+    std::function<void(AbstractSlotTrackerStorage *, const Function *, bool)>
+        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 +4822,17 @@ void ModuleSummaryIndex::print(raw_ostream &ROS, bool IsForDebug) const {
   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/CMakeLists.txt b/llvm/unittests/CMakeLists.txt
index 4076642a217e5..7b3804fb93758 100644
--- a/llvm/unittests/CMakeLists.txt
+++ b/llvm/unittests/CMakeLists.txt
@@ -33,6 +33,7 @@ add_subdirectory(LineEditor)
 add_subdirectory(Linker)
 add_subdirectory(MC)
 add_subdirectory(MI)
+add_subdirectory(MIR)
 add_subdirectory(Object)
 add_subdirectory(ObjectYAML)
 add_subdirectory(Option)

diff  --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index 11706cf62749d..4d78451140470 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
   AsmPrinter
   CodeGen
   Core
+  FileCheck
   MC
   MIRParser
   Passes

diff  --git a/llvm/unittests/MIR/CMakeLists.txt b/llvm/unittests/MIR/CMakeLists.txt
new file mode 100644
index 0000000000000..024317acba3e6
--- /dev/null
+++ b/llvm/unittests/MIR/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(LLVM_LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  CodeGen
+  Core
+  FileCheck
+  MC
+  MIRParser
+  Support
+  Target
+  )
+
+add_llvm_unittest(MIRTests
+  MachineMetadata.cpp
+  )
+
+target_link_libraries(MIRTests PRIVATE LLVMTestingSupport)

diff  --git a/llvm/unittests/MIR/MachineMetadata.cpp b/llvm/unittests/MIR/MachineMetadata.cpp
new file mode 100644
index 0000000000000..091c89b64069d
--- /dev/null
+++ b/llvm/unittests/MIR/MachineMetadata.cpp
@@ -0,0 +1,481 @@
+//===- 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<Module> M;
+  std::unique_ptr<MIRParser> MIR;
+
+  static void SetUpTestCase() {
+    InitializeAllTargetInfos();
+    InitializeAllTargets();
+    InitializeAllTargetMCs();
+  }
+
+  void SetUp() override { M = std::make_unique<Module>("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<LLVMTargetMachine>
+  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<LLVMTargetMachine>(static_cast<LLVMTargetMachine *>(
+        T->createTargetMachine(TT, CPU, FS, Options, None, None)));
+  }
+
+  std::unique_ptr<Module> parseMIR(const TargetMachine &TM, StringRef MIRCode,
+                                   const char *FnName, MachineModuleInfo &MMI) {
+    SMDiagnostic Diagnostic;
+    std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
+    MIR = createMIRParser(std::move(MBuffer), Context);
+    if (!MIR)
+      return nullptr;
+
+    std::unique_ptr<Module> 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<void(raw_ostream &OS)> 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_EQ(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_EQ(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_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<const MDNode *> Generated{Domain, Scope0, Scope1, Set0, Set1};
+  // Examine machine metadata collected. They should match ones
+  // afore-generated.
+  std::vector<const MDNode *> 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<const MDNode *> Generated{Domain, Scope0, Scope1, Set0, Set1};
+  // Examine machine metadata collected. They should match ones
+  // afore-generated.
+  std::vector<const MDNode *> 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<const MDNode *> Generated{Domain, Scope0, Scope1, Set0, Set1};
+  // Examine machine metadata collected. They should match ones
+  // afore-generated.
+  std::vector<const MDNode *> 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));
+}


        


More information about the llvm-commits mailing list