[llvm] e818efa - [MIRParser] Add machine metadata.

Michael Liao via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 28 19:29:48 PDT 2021


Author: Michael Liao
Date: 2021-06-28T22:29:36-04:00
New Revision: e818eface8034040fbea7ce2f05761944b2d53b1

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

LOG: [MIRParser] Add machine metadata.

- Add standalone metadata parsing support so that machine metadata nodes
  could be populated before and accessed during MIR is parsed.

Reviewed By: arsenm

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

Added: 
    llvm/test/CodeGen/MIR/AArch64/machine-metadata-error.mir
    llvm/test/CodeGen/MIR/AArch64/machine-metadata.mir
    llvm/test/CodeGen/MIR/AMDGPU/machine-metadata-error.mir
    llvm/test/CodeGen/MIR/AMDGPU/machine-metadata.mir
    llvm/test/CodeGen/MIR/Generic/machine-metadata-err0.mir
    llvm/test/CodeGen/MIR/Generic/machine-metadata-err1.mir
    llvm/test/CodeGen/MIR/Generic/machine-metadata-err2.mir
    llvm/test/CodeGen/MIR/Generic/machine-metadata-err3.mir
    llvm/test/CodeGen/MIR/Generic/machine-metadata-err4.mir
    llvm/test/CodeGen/MIR/Generic/machine-metadata-err5.mir
    llvm/test/CodeGen/MIR/Generic/machine-metadata-err6.mir
    llvm/test/CodeGen/MIR/Generic/machine-metadata-err7.mir
    llvm/test/CodeGen/MIR/Generic/machine-metadata-err8.mir
    llvm/test/CodeGen/MIR/X86/machine-metadata-error.mir
    llvm/test/CodeGen/MIR/X86/machine-metadata.mir

Modified: 
    llvm/include/llvm/CodeGen/MIRParser/MIParser.h
    llvm/lib/CodeGen/MIRParser/MILexer.cpp
    llvm/lib/CodeGen/MIRParser/MILexer.h
    llvm/lib/CodeGen/MIRParser/MIParser.cpp
    llvm/lib/CodeGen/MIRParser/MIRParser.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/MIRParser/MIParser.h b/llvm/include/llvm/CodeGen/MIRParser/MIParser.h
index e3f7e3df3f1a9..b01a0c7aa073c 100644
--- a/llvm/include/llvm/CodeGen/MIRParser/MIParser.h
+++ b/llvm/include/llvm/CodeGen/MIRParser/MIParser.h
@@ -18,6 +18,8 @@
 #include "llvm/CodeGen/MachineMemOperand.h"
 #include "llvm/CodeGen/Register.h"
 #include "llvm/Support/Allocator.h"
+#include "llvm/Support/SMLoc.h"
+#include <utility>
 
 namespace llvm {
 
@@ -164,6 +166,9 @@ struct PerFunctionMIParsingState {
   const SlotMapping &IRSlots;
   PerTargetMIParsingState &Target;
 
+  std::map<unsigned, TrackingMDNodeRef> MachineMetadataNodes;
+  std::map<unsigned, std::pair<TempMDTuple, SMLoc>> MachineForwardRefMDNodes;
+
   DenseMap<unsigned, MachineBasicBlock *> MBBSlots;
   DenseMap<Register, VRegInfo *> VRegInfos;
   StringMap<VRegInfo *> VRegInfosNamed;
@@ -233,6 +238,9 @@ bool parseStackObjectReference(PerFunctionMIParsingState &PFS, int &FI,
 bool parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, StringRef Src,
                  SMDiagnostic &Error);
 
+bool parseMachineMetadata(PerFunctionMIParsingState &PFS, StringRef Src,
+                          SMRange SourceRange, SMDiagnostic &Error);
+
 } // end namespace llvm
 
 #endif // LLVM_CODEGEN_MIRPARSER_MIPARSER_H

diff  --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index e6866f04986f0..87fde7d39a60d 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -273,6 +273,7 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
       .Case("bbsections", MIToken::kw_bbsections)
       .Case("unknown-size", MIToken::kw_unknown_size)
       .Case("unknown-address", MIToken::kw_unknown_address)
+      .Case("distinct", MIToken::kw_distinct)
       .Default(MIToken::Identifier);
 }
 

diff  --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h
index 5d7ea8fb66284..68425b41c3fb1 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.h
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.h
@@ -129,6 +129,9 @@ struct MIToken {
     kw_unknown_size,
     kw_unknown_address,
 
+    // Metadata types.
+    kw_distinct,
+
     // Named metadata keywords
     md_tbaa,
     md_alias_scope,

diff  --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 745ba4dc7b91d..1368663e93b31 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -395,6 +395,7 @@ class MIParser {
   MachineFunction &MF;
   SMDiagnostic &Error;
   StringRef Source, CurrentSource;
+  SMRange SourceRange;
   MIToken Token;
   PerFunctionMIParsingState &PFS;
   /// Maps from slot numbers to function's unnamed basic blocks.
@@ -403,6 +404,8 @@ class MIParser {
 public:
   MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error,
            StringRef Source);
+  MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error,
+           StringRef Source, SMRange SourceRange);
 
   /// \p SkipChar gives the number of characters to skip before looking
   /// for the next token.
@@ -428,6 +431,10 @@ class MIParser {
   bool parseStandaloneRegister(Register &Reg);
   bool parseStandaloneStackObject(int &FI);
   bool parseStandaloneMDNode(MDNode *&Node);
+  bool parseMachineMetadata();
+  bool parseMDTuple(MDNode *&MD, bool IsDistinct);
+  bool parseMDNodeVector(SmallVectorImpl<Metadata *> &Elts);
+  bool parseMetadata(Metadata *&MD);
 
   bool
   parseBasicBlockDefinition(DenseMap<unsigned, MachineBasicBlock *> &MBBSlots);
@@ -550,6 +557,10 @@ class MIParser {
   /// parseStringConstant
   ///   ::= StringConstant
   bool parseStringConstant(std::string &Result);
+
+  /// Map the location in the MI string to the corresponding location specified
+  /// in `SourceRange`.
+  SMLoc mapSMLoc(StringRef::iterator Loc);
 };
 
 } // end anonymous namespace
@@ -559,6 +570,11 @@ MIParser::MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error,
     : MF(PFS.MF), Error(Error), Source(Source), CurrentSource(Source), PFS(PFS)
 {}
 
+MIParser::MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error,
+                   StringRef Source, SMRange SourceRange)
+    : MF(PFS.MF), Error(Error), Source(Source), CurrentSource(Source),
+      SourceRange(SourceRange), PFS(PFS) {}
+
 void MIParser::lex(unsigned SkipChar) {
   CurrentSource = lexMIToken(
       CurrentSource.slice(SkipChar, StringRef::npos), Token,
@@ -584,6 +600,13 @@ bool MIParser::error(StringRef::iterator Loc, const Twine &Msg) {
   return true;
 }
 
+SMLoc MIParser::mapSMLoc(StringRef::iterator Loc) {
+  assert(SourceRange.isValid() && "Invalid source range");
+  assert(Loc >= Source.data() && Loc <= (Source.data() + Source.size()));
+  return SMLoc::getFromPointer(SourceRange.Start.getPointer() +
+                               (Loc - Source.data()));
+}
+
 typedef function_ref<bool(StringRef::iterator Loc, const Twine &)>
     ErrorCallbackType;
 
@@ -1172,6 +1195,130 @@ bool MIParser::parseStandaloneMDNode(MDNode *&Node) {
   return false;
 }
 
+bool MIParser::parseMachineMetadata() {
+  lex();
+  if (Token.isNot(MIToken::exclaim))
+    return error("expected a metadata node");
+
+  lex();
+  if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned())
+    return error("expected metadata id after '!'");
+  unsigned ID = 0;
+  if (getUnsigned(ID))
+    return true;
+  lex();
+  if (expectAndConsume(MIToken::equal))
+    return true;
+  bool IsDistinct = Token.is(MIToken::kw_distinct);
+  if (IsDistinct)
+    lex();
+  if (Token.isNot(MIToken::exclaim))
+    return error("expected a metadata node");
+  lex();
+
+  MDNode *MD;
+  if (parseMDTuple(MD, IsDistinct))
+    return true;
+
+  auto FI = PFS.MachineForwardRefMDNodes.find(ID);
+  if (FI != PFS.MachineForwardRefMDNodes.end()) {
+    FI->second.first->replaceAllUsesWith(MD);
+    PFS.MachineForwardRefMDNodes.erase(FI);
+
+    assert(PFS.MachineMetadataNodes[ID] == MD && "Tracking VH didn't work");
+  } else {
+    if (PFS.MachineMetadataNodes.count(ID))
+      return error("Metadata id is already used");
+    PFS.MachineMetadataNodes[ID].reset(MD);
+  }
+
+  return false;
+}
+
+bool MIParser::parseMDTuple(MDNode *&MD, bool IsDistinct) {
+  SmallVector<Metadata *, 16> Elts;
+  if (parseMDNodeVector(Elts))
+    return true;
+  MD = (IsDistinct ? MDTuple::getDistinct
+                   : MDTuple::get)(MF.getFunction().getContext(), Elts);
+  return false;
+}
+
+bool MIParser::parseMDNodeVector(SmallVectorImpl<Metadata *> &Elts) {
+  if (Token.isNot(MIToken::lbrace))
+    return error("expected '{' here");
+  lex();
+
+  if (Token.is(MIToken::rbrace)) {
+    lex();
+    return false;
+  }
+
+  do {
+    Metadata *MD;
+    if (parseMetadata(MD))
+      return true;
+
+    Elts.push_back(MD);
+
+    if (Token.isNot(MIToken::comma))
+      break;
+    lex();
+  } while (true);
+
+  if (Token.isNot(MIToken::rbrace))
+    return error("expected end of metadata node");
+  lex();
+
+  return false;
+}
+
+// ::= !42
+// ::= !"string"
+bool MIParser::parseMetadata(Metadata *&MD) {
+  if (Token.isNot(MIToken::exclaim))
+    return error("expected '!' here");
+  lex();
+
+  if (Token.is(MIToken::StringConstant)) {
+    std::string Str;
+    if (parseStringConstant(Str))
+      return true;
+    MD = MDString::get(MF.getFunction().getContext(), Str);
+    return false;
+  }
+
+  if (Token.isNot(MIToken::IntegerLiteral) || Token.integerValue().isSigned())
+    return error("expected metadata id after '!'");
+
+  SMLoc Loc = mapSMLoc(Token.location());
+
+  unsigned ID = 0;
+  if (getUnsigned(ID))
+    return true;
+  lex();
+
+  auto NodeInfo = PFS.IRSlots.MetadataNodes.find(ID);
+  if (NodeInfo != PFS.IRSlots.MetadataNodes.end()) {
+    MD = NodeInfo->second.get();
+    return false;
+  }
+  // Check machine metadata.
+  NodeInfo = PFS.MachineMetadataNodes.find(ID);
+  if (NodeInfo != PFS.MachineMetadataNodes.end()) {
+    MD = NodeInfo->second.get();
+    return false;
+  }
+  // Forward reference.
+  auto &FwdRef = PFS.MachineForwardRefMDNodes[ID];
+  FwdRef = std::make_pair(
+      MDTuple::getTemporary(MF.getFunction().getContext(), None), Loc);
+  PFS.MachineMetadataNodes[ID].reset(FwdRef.first.get());
+  MD = FwdRef.first.get();
+
+  return false;
+}
+
 static const char *printImplicitRegisterFlag(const MachineOperand &MO) {
   assert(MO.isImplicit());
   return MO.isDef() ? "implicit-def" : "implicit";
@@ -2014,8 +2161,11 @@ bool MIParser::parseMDNode(MDNode *&Node) {
   if (getUnsigned(ID))
     return true;
   auto NodeInfo = PFS.IRSlots.MetadataNodes.find(ID);
-  if (NodeInfo == PFS.IRSlots.MetadataNodes.end())
-    return error(Loc, "use of undefined metadata '!" + Twine(ID) + "'");
+  if (NodeInfo == PFS.IRSlots.MetadataNodes.end()) {
+    NodeInfo = PFS.MachineMetadataNodes.find(ID);
+    if (NodeInfo == PFS.MachineMetadataNodes.end())
+      return error(Loc, "use of undefined metadata '!" + Twine(ID) + "'");
+  }
   lex();
   Node = NodeInfo->second.get();
   return false;
@@ -3281,6 +3431,11 @@ bool llvm::parseMDNode(PerFunctionMIParsingState &PFS,
   return MIParser(PFS, Error, Src).parseStandaloneMDNode(Node);
 }
 
+bool llvm::parseMachineMetadata(PerFunctionMIParsingState &PFS, StringRef Src,
+                                SMRange SrcRange, SMDiagnostic &Error) {
+  return MIParser(PFS, Error, Src, SrcRange).parseMachineMetadata();
+}
+
 bool MIRFormatter::parseIRValue(StringRef Src, MachineFunction &MF,
                                 PerFunctionMIParsingState &PFS, const Value *&V,
                                 ErrorCallbackType ErrorCallback) {

diff  --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
index 88dc4571b2d77..58ce95aaf023c 100644
--- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -143,6 +143,10 @@ class MIRParserImpl {
   bool initializeJumpTableInfo(PerFunctionMIParsingState &PFS,
                                const yaml::MachineJumpTable &YamlJTI);
 
+  bool parseMachineMetadataNodes(PerFunctionMIParsingState &PFS,
+                                 MachineFunction &MF,
+                                 const yaml::MachineFunction &YMF);
+
 private:
   bool parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node,
                    const yaml::StringValue &Source);
@@ -151,6 +155,9 @@ class MIRParserImpl {
                          MachineBasicBlock *&MBB,
                          const yaml::StringValue &Source);
 
+  bool parseMachineMetadata(PerFunctionMIParsingState &PFS,
+                            const yaml::StringValue &Source);
+
   /// Return a MIR diagnostic converted from an MI string diagnostic.
   SMDiagnostic diagFromMIStringDiag(const SMDiagnostic &Error,
                                     SMRange SourceRange);
@@ -457,6 +464,9 @@ MIRParserImpl::initializeMachineFunction(const yaml::MachineFunction &YamlMF,
     if (initializeConstantPool(PFS, *ConstantPool, YamlMF))
       return true;
   }
+  if (!YamlMF.MachineMetadataNodes.empty() &&
+      parseMachineMetadataNodes(PFS, MF, YamlMF))
+    return true;
 
   StringRef BlockStr = YamlMF.Body.Value.Value;
   SMDiagnostic Error;
@@ -920,6 +930,29 @@ bool MIRParserImpl::parseMBBReference(PerFunctionMIParsingState &PFS,
   return false;
 }
 
+bool MIRParserImpl::parseMachineMetadata(PerFunctionMIParsingState &PFS,
+                                         const yaml::StringValue &Source) {
+  SMDiagnostic Error;
+  if (llvm::parseMachineMetadata(PFS, Source.Value, Source.SourceRange, Error))
+    return error(Error, Source.SourceRange);
+  return false;
+}
+
+bool MIRParserImpl::parseMachineMetadataNodes(
+    PerFunctionMIParsingState &PFS, MachineFunction &MF,
+    const yaml::MachineFunction &YMF) {
+  for (auto &MDS : YMF.MachineMetadataNodes) {
+    if (parseMachineMetadata(PFS, MDS))
+      return true;
+  }
+  // Report missing definitions from forward referenced nodes.
+  if (!PFS.MachineForwardRefMDNodes.empty())
+    return error(PFS.MachineForwardRefMDNodes.begin()->second.second,
+                 "use of undefined metadata '!" +
+                     Twine(PFS.MachineForwardRefMDNodes.begin()->first) + "'");
+  return false;
+}
+
 SMDiagnostic MIRParserImpl::diagFromMIStringDiag(const SMDiagnostic &Error,
                                                  SMRange SourceRange) {
   assert(SourceRange.isValid() && "Invalid source range");

diff  --git a/llvm/test/CodeGen/MIR/AArch64/machine-metadata-error.mir b/llvm/test/CodeGen/MIR/AArch64/machine-metadata-error.mir
new file mode 100644
index 0000000000000..faf9c6a73ab03
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AArch64/machine-metadata-error.mir
@@ -0,0 +1,25 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+--- |
+  target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+  target triple = "aarch64-unknown-linux-gnu"
+
+  define i32 @test_memcpy(i32* nocapture %p, i32* nocapture readonly %q) {
+    ret i32 0
+  }
+...
+---
+name:            test_memcpy
+machineMetadataNodes:
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!10 = !{!9}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+  - '!5 = !{!6}'
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+body:             |
+  bb.0 (%ir-block.0):
+  ; CHECK: [[@LINE+1]]:78: use of undefined metadata '!11'
+    %2:fpr128 = LDRQui %0, 1 :: (load 16, align 4, !alias.scope !5, !noalias !11)
+
+...

diff  --git a/llvm/test/CodeGen/MIR/AArch64/machine-metadata.mir b/llvm/test/CodeGen/MIR/AArch64/machine-metadata.mir
new file mode 100644
index 0000000000000..1dfc45d6546a8
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AArch64/machine-metadata.mir
@@ -0,0 +1,166 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=aarch64-linux-gnu -run-pass=none -o - %s | FileCheck %s
+--- |
+  ; ModuleID = 'test/CodeGen/AArch64/memcpy-scoped-aa.ll'
+  source_filename = "test/CodeGen/AArch64/memcpy-scoped-aa.ll"
+  target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+  target triple = "aarch64-unknown-linux-gnu"
+
+  define i32 @test_memcpy(i32* nocapture %p, i32* nocapture readonly %q) {
+    %p0 = bitcast i32* %p to i8*
+    %add.ptr = getelementptr inbounds i32, i32* %p, i64 4
+    %p1 = bitcast i32* %add.ptr to i8*
+    tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 4 dereferenceable(16) %p0, i8* noundef nonnull align 4 dereferenceable(16) %p1, i64 16, i1 false), !alias.scope !0, !noalias !3
+    %v0 = load i32, i32* %q, align 4, !alias.scope !3, !noalias !0
+    %q1 = getelementptr inbounds i32, i32* %q, i64 1
+    %v1 = load i32, i32* %q1, align 4, !alias.scope !3, !noalias !0
+    %add = add i32 %v0, %v1
+    ret i32 %add
+  }
+
+  define i32 @test_memcpy_inline(i32* nocapture %p, i32* nocapture readonly %q) {
+    %p0 = bitcast i32* %p to i8*
+    %add.ptr = getelementptr inbounds i32, i32* %p, i64 4
+    %p1 = bitcast i32* %add.ptr to i8*
+    tail call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* noundef nonnull align 4 dereferenceable(16) %p0, i8* noundef nonnull align 4 dereferenceable(16) %p1, i64 16, i1 false), !alias.scope !0, !noalias !3
+    %v0 = load i32, i32* %q, align 4, !alias.scope !3, !noalias !0
+    %q1 = getelementptr inbounds i32, i32* %q, i64 1
+    %v1 = load i32, i32* %q1, align 4, !alias.scope !3, !noalias !0
+    %add = add i32 %v0, %v1
+    ret i32 %add
+  }
+
+  define i32 @test_mempcpy(i32* nocapture %p, i32* nocapture readonly %q) {
+    %p0 = bitcast i32* %p to i8*
+    %add.ptr = getelementptr inbounds i32, i32* %p, i64 4
+    %p1 = bitcast i32* %add.ptr to i8*
+    %call = tail call i8* @mempcpy(i8* noundef nonnull align 4 dereferenceable(16) %p0, i8* noundef nonnull align 4 dereferenceable(16) %p1, i64 16), !alias.scope !0, !noalias !3
+    %v0 = load i32, i32* %q, align 4, !alias.scope !3, !noalias !0
+    %q1 = getelementptr inbounds i32, i32* %q, i64 1
+    %v1 = load i32, i32* %q1, align 4, !alias.scope !3, !noalias !0
+    %add = add i32 %v0, %v1
+    ret i32 %add
+  }
+
+  ; Function Attrs: argmemonly nofree nounwind willreturn
+  declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0
+
+  ; Function Attrs: argmemonly nofree nounwind willreturn
+  declare void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64 immarg, i1 immarg) #0
+
+  declare i8* @mempcpy(i8*, i8*, i64)
+
+  attributes #0 = { argmemonly nofree nounwind willreturn }
+
+  !0 = !{!1}
+  !1 = distinct !{!1, !2, !"bax: %p"}
+  !2 = distinct !{!2, !"bax"}
+  !3 = !{!4}
+  !4 = distinct !{!4, !2, !"bax: %q"}
+
+...
+---
+name:            test_memcpy
+machineMetadataNodes:
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!10 = !{!1, !9}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+  - '!5 = !{!1, !6}'
+  - '!11 = !{!4, !6}'
+  - '!8 = !{!4, !9}'
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+body:             |
+  bb.0 (%ir-block.0):
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memcpy
+    ; CHECK: [[COPY:%[0-9]+]]:gpr64common = COPY $x1
+    ; CHECK: [[COPY1:%[0-9]+]]:gpr64common = COPY $x0
+    ; CHECK: [[LDRQui:%[0-9]+]]:fpr128 = LDRQui [[COPY1]], 1 :: (load 16 from %ir.p1, align 4, !alias.scope !5, !noalias !8)
+    ; CHECK: STRQui killed [[LDRQui]], [[COPY1]], 0 :: (store 16 into %ir.p0, align 4, !alias.scope !10, !noalias !11)
+    ; CHECK: [[LDRWui:%[0-9]+]]:gpr32 = LDRWui [[COPY]], 0 :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    ; CHECK: [[LDRWui1:%[0-9]+]]:gpr32 = LDRWui [[COPY]], 1 :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    ; CHECK: [[ADDWrr:%[0-9]+]]:gpr32 = ADDWrr killed [[LDRWui]], killed [[LDRWui1]]
+    ; CHECK: $w0 = COPY [[ADDWrr]]
+    ; CHECK: RET_ReallyLR implicit $w0
+    %1:gpr64common = COPY $x1
+    %0:gpr64common = COPY $x0
+    %2:fpr128 = LDRQui %0, 1 :: (load 16 from %ir.p1, align 4, !alias.scope !5, !noalias !8)
+    STRQui killed %2, %0, 0 :: (store 16 into %ir.p0, align 4, !alias.scope !10, !noalias !11)
+    %3:gpr32 = LDRWui %1, 0 :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    %4:gpr32 = LDRWui %1, 1 :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    %5:gpr32 = ADDWrr killed %3, killed %4
+    $w0 = COPY %5
+    RET_ReallyLR implicit $w0
+
+...
+---
+name:            test_memcpy_inline
+machineMetadataNodes:
+  - '!10 = !{!1, !9}'
+  - '!5 = !{!1, !6}'
+  - '!8 = !{!4, !9}'
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!11 = !{!4, !6}'
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+body:             |
+  bb.0 (%ir-block.0):
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_memcpy_inline
+    ; CHECK: [[COPY:%[0-9]+]]:gpr64common = COPY $x1
+    ; CHECK: [[COPY1:%[0-9]+]]:gpr64common = COPY $x0
+    ; CHECK: [[LDRQui:%[0-9]+]]:fpr128 = LDRQui [[COPY1]], 1 :: (load 16 from %ir.p1, align 4, !alias.scope !5, !noalias !8)
+    ; CHECK: STRQui killed [[LDRQui]], [[COPY1]], 0 :: (store 16 into %ir.p0, align 4, !alias.scope !10, !noalias !11)
+    ; CHECK: [[LDRWui:%[0-9]+]]:gpr32 = LDRWui [[COPY]], 0 :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    ; CHECK: [[LDRWui1:%[0-9]+]]:gpr32 = LDRWui [[COPY]], 1 :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    ; CHECK: [[ADDWrr:%[0-9]+]]:gpr32 = ADDWrr killed [[LDRWui]], killed [[LDRWui1]]
+    ; CHECK: $w0 = COPY [[ADDWrr]]
+    ; CHECK: RET_ReallyLR implicit $w0
+    %1:gpr64common = COPY $x1
+    %0:gpr64common = COPY $x0
+    %2:fpr128 = LDRQui %0, 1 :: (load 16 from %ir.p1, align 4, !alias.scope !5, !noalias !8)
+    STRQui killed %2, %0, 0 :: (store 16 into %ir.p0, align 4, !alias.scope !10, !noalias !11)
+    %3:gpr32 = LDRWui %1, 0 :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    %4:gpr32 = LDRWui %1, 1 :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    %5:gpr32 = ADDWrr killed %3, killed %4
+    $w0 = COPY %5
+    RET_ReallyLR implicit $w0
+
+...
+---
+name:            test_mempcpy
+machineMetadataNodes:
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!8 = !{!4, !9}'
+  - '!5 = !{!1, !6}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+  - '!11 = !{!4, !6}'
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+  - '!10 = !{!1, !9}'
+body:             |
+  bb.0 (%ir-block.0):
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: test_mempcpy
+    ; CHECK: [[COPY:%[0-9]+]]:gpr64common = COPY $x1
+    ; CHECK: [[COPY1:%[0-9]+]]:gpr64common = COPY $x0
+    ; CHECK: [[LDRQui:%[0-9]+]]:fpr128 = LDRQui [[COPY1]], 1 :: (load 16 from %ir.p1, align 1, !alias.scope !5, !noalias !8)
+    ; CHECK: STRQui killed [[LDRQui]], [[COPY1]], 0 :: (store 16 into %ir.p0, align 1, !alias.scope !10, !noalias !11)
+    ; CHECK: [[LDRWui:%[0-9]+]]:gpr32 = LDRWui [[COPY]], 0 :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    ; CHECK: [[LDRWui1:%[0-9]+]]:gpr32 = LDRWui [[COPY]], 1 :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    ; CHECK: [[ADDWrr:%[0-9]+]]:gpr32 = ADDWrr killed [[LDRWui]], killed [[LDRWui1]]
+    ; CHECK: $w0 = COPY [[ADDWrr]]
+    ; CHECK: RET_ReallyLR implicit $w0
+    %1:gpr64common = COPY $x1
+    %0:gpr64common = COPY $x0
+    %2:fpr128 = LDRQui %0, 1 :: (load 16 from %ir.p1, align 1, !alias.scope !5, !noalias !8)
+    STRQui killed %2, %0, 0 :: (store 16 into %ir.p0, align 1, !alias.scope !10, !noalias !11)
+    %3:gpr32 = LDRWui %1, 0 :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    %4:gpr32 = LDRWui %1, 1 :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    %5:gpr32 = ADDWrr killed %3, killed %4
+    $w0 = COPY %5
+    RET_ReallyLR implicit $w0
+
+...

diff  --git a/llvm/test/CodeGen/MIR/AMDGPU/machine-metadata-error.mir b/llvm/test/CodeGen/MIR/AMDGPU/machine-metadata-error.mir
new file mode 100644
index 0000000000000..60dabbd7178a5
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/machine-metadata-error.mir
@@ -0,0 +1,25 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+--- |
+  target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7"
+  target triple = "amdgcn-amd-amdhsa"
+
+  define i32 @test_memcpy(i32 addrspace(1)* nocapture %p, i32 addrspace(1)* nocapture readonly %q) #0 {
+    ret i32 0
+  }
+...
+---
+name:            test_memcpy
+machineMetadataNodes:
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+  - '!5 = !{!6}'
+  - '!10 = !{!9}'
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+body:             |
+  bb.0 (%ir-block.0):
+  ; CHECK: [[@LINE+1]]:113: use of undefined metadata '!11'
+    %8:vreg_128 = GLOBAL_LOAD_DWORDX4 %9, 16, 0, implicit $exec :: (load 16, align 4, !alias.scope !5, !noalias !11, addrspace 1)
+
+...

diff  --git a/llvm/test/CodeGen/MIR/AMDGPU/machine-metadata.mir b/llvm/test/CodeGen/MIR/AMDGPU/machine-metadata.mir
new file mode 100644
index 0000000000000..74ea99465185a
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/AMDGPU/machine-metadata.mir
@@ -0,0 +1,181 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 -run-pass=none -o - %s | FileCheck %s
+--- |
+  ; ModuleID = 'test/CodeGen/AMDGPU/memcpy-scoped-aa.ll'
+  source_filename = "test/CodeGen/AMDGPU/memcpy-scoped-aa.ll"
+  target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7"
+  target triple = "amdgcn-amd-amdhsa"
+
+  define i32 @test_memcpy(i32 addrspace(1)* nocapture %p, i32 addrspace(1)* nocapture readonly %q) #0 {
+    %p0 = bitcast i32 addrspace(1)* %p to i8 addrspace(1)*
+    %add.ptr = getelementptr inbounds i32, i32 addrspace(1)* %p, i64 4
+    %p1 = bitcast i32 addrspace(1)* %add.ptr to i8 addrspace(1)*
+    tail call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* noundef nonnull align 4 dereferenceable(16) %p0, i8 addrspace(1)* noundef nonnull align 4 dereferenceable(16) %p1, i64 16, i1 false), !alias.scope !0, !noalias !3
+    %1 = bitcast i32 addrspace(1)* %q to <2 x i32> addrspace(1)*
+    %2 = load <2 x i32>, <2 x i32> addrspace(1)* %1, align 4, !alias.scope !3, !noalias !0
+    %v01 = extractelement <2 x i32> %2, i32 0
+    %v12 = extractelement <2 x i32> %2, i32 1
+    %add = add i32 %v01, %v12
+    ret i32 %add
+  }
+
+  define i32 @test_memcpy_inline(i32 addrspace(1)* nocapture %p, i32 addrspace(1)* nocapture readonly %q) #0 {
+    %p0 = bitcast i32 addrspace(1)* %p to i8 addrspace(1)*
+    %add.ptr = getelementptr inbounds i32, i32 addrspace(1)* %p, i64 4
+    %p1 = bitcast i32 addrspace(1)* %add.ptr to i8 addrspace(1)*
+    tail call void @llvm.memcpy.inline.p1i8.p1i8.i64(i8 addrspace(1)* noundef nonnull align 4 dereferenceable(16) %p0, i8 addrspace(1)* noundef nonnull align 4 dereferenceable(16) %p1, i64 16, i1 false), !alias.scope !0, !noalias !3
+    %1 = bitcast i32 addrspace(1)* %q to <2 x i32> addrspace(1)*
+    %2 = load <2 x i32>, <2 x i32> addrspace(1)* %1, align 4, !alias.scope !3, !noalias !0
+    %v01 = extractelement <2 x i32> %2, i32 0
+    %v12 = extractelement <2 x i32> %2, i32 1
+    %add = add i32 %v01, %v12
+    ret i32 %add
+  }
+
+  ; Function Attrs: argmemonly nofree nounwind willreturn
+  declare void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* noalias nocapture writeonly, i8 addrspace(1)* noalias nocapture readonly, i64, i1 immarg) #1
+
+  ; Function Attrs: argmemonly nofree nounwind willreturn
+  declare void @llvm.memcpy.inline.p1i8.p1i8.i64(i8 addrspace(1)* noalias nocapture writeonly, i8 addrspace(1)* noalias nocapture readonly, i64 immarg, i1 immarg) #1
+
+  ; Function Attrs: convergent nounwind willreturn
+  declare { i1, i32 } @llvm.amdgcn.if.i32(i1) #2
+
+  ; Function Attrs: convergent nounwind willreturn
+  declare { i1, i32 } @llvm.amdgcn.else.i32.i32(i32) #2
+
+  ; Function Attrs: convergent nounwind readnone willreturn
+  declare i32 @llvm.amdgcn.if.break.i32(i1, i32) #3
+
+  ; Function Attrs: convergent nounwind willreturn
+  declare i1 @llvm.amdgcn.loop.i32(i32) #2
+
+  ; Function Attrs: convergent nounwind willreturn
+  declare void @llvm.amdgcn.end.cf.i32(i32) #2
+
+  attributes #0 = { "target-cpu"="gfx1010" }
+  attributes #1 = { argmemonly nofree nounwind willreturn "target-cpu"="gfx1010" }
+  attributes #2 = { convergent nounwind willreturn }
+  attributes #3 = { convergent nounwind readnone willreturn }
+
+  !0 = !{!1}
+  !1 = distinct !{!1, !2, !"bax: %p"}
+  !2 = distinct !{!2, !"bax"}
+  !3 = !{!4}
+  !4 = distinct !{!4, !2, !"bax: %q"}
+
+...
+---
+name:            test_memcpy
+machineMetadataNodes:
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+  - '!11 = !{!4, !6}'
+  - '!5 = !{!1, !6}'
+  - '!8 = !{!4, !9}'
+  - '!10 = !{!1, !9}'
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+body:             |
+  bb.0 (%ir-block.0):
+    liveins: $vgpr0, $vgpr1, $vgpr2, $vgpr3, $sgpr30_sgpr31
+
+    ; CHECK-LABEL: name: test_memcpy
+    ; CHECK: [[COPY:%[0-9]+]]:sreg_64 = COPY $sgpr30_sgpr31
+    ; CHECK: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr3
+    ; CHECK: [[COPY2:%[0-9]+]]:vgpr_32 = COPY $vgpr2
+    ; CHECK: [[COPY3:%[0-9]+]]:vgpr_32 = COPY $vgpr1
+    ; CHECK: [[COPY4:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+    ; CHECK: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[COPY2]], %subreg.sub0, [[COPY1]], %subreg.sub1
+    ; CHECK: [[REG_SEQUENCE1:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[COPY4]], %subreg.sub0, [[COPY3]], %subreg.sub1
+    ; CHECK: [[COPY5:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE1]]
+    ; CHECK: [[GLOBAL_LOAD_DWORDX4_:%[0-9]+]]:vreg_128 = GLOBAL_LOAD_DWORDX4 [[COPY5]], 16, 0, implicit $exec :: (load 16 from %ir.p1, align 4, !alias.scope !5, !noalias !8, addrspace 1)
+    ; CHECK: [[COPY6:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE1]]
+    ; CHECK: GLOBAL_STORE_DWORDX4 [[COPY6]], killed [[GLOBAL_LOAD_DWORDX4_]], 0, 0, implicit $exec :: (store 16 into %ir.p0, align 4, !alias.scope !10, !noalias !11, addrspace 1)
+    ; CHECK: [[COPY7:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE]]
+    ; CHECK: [[GLOBAL_LOAD_DWORDX2_:%[0-9]+]]:vreg_64 = GLOBAL_LOAD_DWORDX2 killed [[COPY7]], 0, 0, implicit $exec :: (load 8 from %ir.1, align 4, !alias.scope !3, !noalias !0, addrspace 1)
+    ; CHECK: [[COPY8:%[0-9]+]]:vgpr_32 = COPY [[GLOBAL_LOAD_DWORDX2_]].sub0
+    ; CHECK: [[COPY9:%[0-9]+]]:vgpr_32 = COPY [[GLOBAL_LOAD_DWORDX2_]].sub1
+    ; CHECK: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 killed [[COPY8]], killed [[COPY9]], 0, implicit $exec
+    ; CHECK: [[COPY10:%[0-9]+]]:ccr_sgpr_64 = COPY [[COPY]]
+    ; CHECK: $vgpr0 = COPY [[V_ADD_U32_e64_]]
+    ; CHECK: [[COPY11:%[0-9]+]]:ccr_sgpr_64 = COPY [[COPY10]]
+    ; CHECK: S_SETPC_B64_return [[COPY11]], implicit $vgpr0
+    %4:sreg_64 = COPY $sgpr30_sgpr31
+    %3:vgpr_32 = COPY $vgpr3
+    %2:vgpr_32 = COPY $vgpr2
+    %1:vgpr_32 = COPY $vgpr1
+    %0:vgpr_32 = COPY $vgpr0
+    %17:vreg_64 = REG_SEQUENCE %2, %subreg.sub0, %3, %subreg.sub1
+    %18:vreg_64 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1
+    %9:vreg_64 = COPY %18
+    %8:vreg_128 = GLOBAL_LOAD_DWORDX4 %9, 16, 0, implicit $exec :: (load 16 from %ir.p1, align 4, !alias.scope !5, !noalias !8, addrspace 1)
+    %10:vreg_64 = COPY %18
+    GLOBAL_STORE_DWORDX4 %10, killed %8, 0, 0, implicit $exec :: (store 16 into %ir.p0, align 4, !alias.scope !10, !noalias !11, addrspace 1)
+    %12:vreg_64 = COPY %17
+    %11:vreg_64 = GLOBAL_LOAD_DWORDX2 killed %12, 0, 0, implicit $exec :: (load 8 from %ir.1, align 4, !alias.scope !3, !noalias !0, addrspace 1)
+    %13:vgpr_32 = COPY %11.sub0
+    %14:vgpr_32 = COPY %11.sub1
+    %15:vgpr_32 = V_ADD_U32_e64 killed %13, killed %14, 0, implicit $exec
+    %5:ccr_sgpr_64 = COPY %4
+    $vgpr0 = COPY %15
+    %16:ccr_sgpr_64 = COPY %5
+    S_SETPC_B64_return %16, implicit $vgpr0
+
+...
+---
+name:            test_memcpy_inline
+machineMetadataNodes:
+  - '!6 = distinct !{!6, !7, !"Src"}'
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!11 = !{!4, !6}'
+  - '!5 = !{!1, !6}'
+  - '!8 = !{!4, !9}'
+  - '!10 = !{!1, !9}'
+body:             |
+  bb.0 (%ir-block.0):
+    liveins: $vgpr0, $vgpr1, $vgpr2, $vgpr3, $sgpr30_sgpr31
+
+    ; CHECK-LABEL: name: test_memcpy_inline
+    ; CHECK: [[COPY:%[0-9]+]]:sreg_64 = COPY $sgpr30_sgpr31
+    ; CHECK: [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr3
+    ; CHECK: [[COPY2:%[0-9]+]]:vgpr_32 = COPY $vgpr2
+    ; CHECK: [[COPY3:%[0-9]+]]:vgpr_32 = COPY $vgpr1
+    ; CHECK: [[COPY4:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+    ; CHECK: [[REG_SEQUENCE:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[COPY2]], %subreg.sub0, [[COPY1]], %subreg.sub1
+    ; CHECK: [[REG_SEQUENCE1:%[0-9]+]]:vreg_64 = REG_SEQUENCE [[COPY4]], %subreg.sub0, [[COPY3]], %subreg.sub1
+    ; CHECK: [[COPY5:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE1]]
+    ; CHECK: [[GLOBAL_LOAD_DWORDX4_:%[0-9]+]]:vreg_128 = GLOBAL_LOAD_DWORDX4 [[COPY5]], 16, 0, implicit $exec :: (load 16 from %ir.p1, align 4, !alias.scope !5, !noalias !8, addrspace 1)
+    ; CHECK: [[COPY6:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE1]]
+    ; CHECK: GLOBAL_STORE_DWORDX4 [[COPY6]], killed [[GLOBAL_LOAD_DWORDX4_]], 0, 0, implicit $exec :: (store 16 into %ir.p0, align 4, !alias.scope !10, !noalias !11, addrspace 1)
+    ; CHECK: [[COPY7:%[0-9]+]]:vreg_64 = COPY [[REG_SEQUENCE]]
+    ; CHECK: [[GLOBAL_LOAD_DWORDX2_:%[0-9]+]]:vreg_64 = GLOBAL_LOAD_DWORDX2 killed [[COPY7]], 0, 0, implicit $exec :: (load 8 from %ir.1, align 4, !alias.scope !3, !noalias !0, addrspace 1)
+    ; CHECK: [[COPY8:%[0-9]+]]:vgpr_32 = COPY [[GLOBAL_LOAD_DWORDX2_]].sub0
+    ; CHECK: [[COPY9:%[0-9]+]]:vgpr_32 = COPY [[GLOBAL_LOAD_DWORDX2_]].sub1
+    ; CHECK: [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 killed [[COPY8]], killed [[COPY9]], 0, implicit $exec
+    ; CHECK: [[COPY10:%[0-9]+]]:ccr_sgpr_64 = COPY [[COPY]]
+    ; CHECK: $vgpr0 = COPY [[V_ADD_U32_e64_]]
+    ; CHECK: [[COPY11:%[0-9]+]]:ccr_sgpr_64 = COPY [[COPY10]]
+    ; CHECK: S_SETPC_B64_return [[COPY11]], implicit $vgpr0
+    %4:sreg_64 = COPY $sgpr30_sgpr31
+    %3:vgpr_32 = COPY $vgpr3
+    %2:vgpr_32 = COPY $vgpr2
+    %1:vgpr_32 = COPY $vgpr1
+    %0:vgpr_32 = COPY $vgpr0
+    %17:vreg_64 = REG_SEQUENCE %2, %subreg.sub0, %3, %subreg.sub1
+    %18:vreg_64 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1
+    %9:vreg_64 = COPY %18
+    %8:vreg_128 = GLOBAL_LOAD_DWORDX4 %9, 16, 0, implicit $exec :: (load 16 from %ir.p1, align 4, !alias.scope !5, !noalias !8, addrspace 1)
+    %10:vreg_64 = COPY %18
+    GLOBAL_STORE_DWORDX4 %10, killed %8, 0, 0, implicit $exec :: (store 16 into %ir.p0, align 4, !alias.scope !10, !noalias !11, addrspace 1)
+    %12:vreg_64 = COPY %17
+    %11:vreg_64 = GLOBAL_LOAD_DWORDX2 killed %12, 0, 0, implicit $exec :: (load 8 from %ir.1, align 4, !alias.scope !3, !noalias !0, addrspace 1)
+    %13:vgpr_32 = COPY %11.sub0
+    %14:vgpr_32 = COPY %11.sub1
+    %15:vgpr_32 = V_ADD_U32_e64 killed %13, killed %14, 0, implicit $exec
+    %5:ccr_sgpr_64 = COPY %4
+    $vgpr0 = COPY %15
+    %16:ccr_sgpr_64 = COPY %5
+    S_SETPC_B64_return %16, implicit $vgpr0
+
+...

diff  --git a/llvm/test/CodeGen/MIR/Generic/machine-metadata-err0.mir b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err0.mir
new file mode 100644
index 0000000000000..0502ac90e51eb
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err0.mir
@@ -0,0 +1,15 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+
+--- |
+  define i32 @t0() {
+    ret i32 0
+  }
+...
+---
+name: t0
+machineMetadataNodes:
+  - '9 = distinct !{!9, !7, !"Dst"}'
+...
+# CHECK: [[@LINE-2]]:6: expected a metadata node

diff  --git a/llvm/test/CodeGen/MIR/Generic/machine-metadata-err1.mir b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err1.mir
new file mode 100644
index 0000000000000..4ac5202527d2f
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err1.mir
@@ -0,0 +1,15 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+
+--- |
+  define i32 @t0() {
+    ret i32 0
+  }
+...
+---
+name: t0
+machineMetadataNodes:
+  - '! = distinct !{!9, !7, !"Dst"}'
+...
+# CHECK: [[@LINE-2]]:8: expected metadata id after '!'

diff  --git a/llvm/test/CodeGen/MIR/Generic/machine-metadata-err2.mir b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err2.mir
new file mode 100644
index 0000000000000..0e731b12c6456
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err2.mir
@@ -0,0 +1,15 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+
+--- |
+  define i32 @t0() {
+    ret i32 0
+  }
+...
+---
+name: t0
+machineMetadataNodes:
+  - '!9 = distinct {!9, !7, !"Dst"}'
+...
+# CHECK: [[@LINE-2]]:20: expected a metadata node

diff  --git a/llvm/test/CodeGen/MIR/Generic/machine-metadata-err3.mir b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err3.mir
new file mode 100644
index 0000000000000..deb06f5f4abaa
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err3.mir
@@ -0,0 +1,16 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+
+--- |
+  define i32 @t0() {
+    ret i32 0
+  }
+...
+---
+name: t0
+machineMetadataNodes:
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!9 = distinct !{!9, !7, !"Src"}'
+...
+# CHECK: [[@LINE-2]]:37: Metadata id is already used

diff  --git a/llvm/test/CodeGen/MIR/Generic/machine-metadata-err4.mir b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err4.mir
new file mode 100644
index 0000000000000..a28f631b0df00
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err4.mir
@@ -0,0 +1,15 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+
+--- |
+  define i32 @t0() {
+    ret i32 0
+  }
+...
+---
+name: t0
+machineMetadataNodes:
+  - '!9 = distinct !!9, !7, !"Dst"}'
+...
+# CHECK: [[@LINE-2]]:21: expected '{' here

diff  --git a/llvm/test/CodeGen/MIR/Generic/machine-metadata-err5.mir b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err5.mir
new file mode 100644
index 0000000000000..68ab8bc58d864
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err5.mir
@@ -0,0 +1,15 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+
+--- |
+  define i32 @t0() {
+    ret i32 0
+  }
+...
+---
+name: t0
+machineMetadataNodes:
+  - '!9 = distinct !{!9, !7, !"Dst"'
+...
+# CHECK: [[@LINE-2]]:36: expected end of metadata node

diff  --git a/llvm/test/CodeGen/MIR/Generic/machine-metadata-err6.mir b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err6.mir
new file mode 100644
index 0000000000000..51cca1b259cd0
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err6.mir
@@ -0,0 +1,15 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+
+--- |
+  define i32 @t0() {
+    ret i32 0
+  }
+...
+---
+name: t0
+machineMetadataNodes:
+  - '!9 = distinct !{9, !7, !"Dst"}'
+...
+# CHECK: [[@LINE-2]]:22: expected '!' here

diff  --git a/llvm/test/CodeGen/MIR/Generic/machine-metadata-err7.mir b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err7.mir
new file mode 100644
index 0000000000000..0cc5ef1b8af83
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err7.mir
@@ -0,0 +1,15 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+
+--- |
+  define i32 @t0() {
+    ret i32 0
+  }
+...
+---
+name: t0
+machineMetadataNodes:
+  - '!9 = distinct !{!, !7, !"Dst"}'
+...
+# CHECK: [[@LINE-2]]:23: expected metadata id after '!'

diff  --git a/llvm/test/CodeGen/MIR/Generic/machine-metadata-err8.mir b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err8.mir
new file mode 100644
index 0000000000000..1d51dbc5d659d
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/Generic/machine-metadata-err8.mir
@@ -0,0 +1,15 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+
+--- |
+  define i32 @t0() {
+    ret i32 0
+  }
+...
+---
+name: t0
+machineMetadataNodes:
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+...
+# CHECK: [[@LINE-2]]:26: use of undefined metadata '!7'

diff  --git a/llvm/test/CodeGen/MIR/X86/machine-metadata-error.mir b/llvm/test/CodeGen/MIR/X86/machine-metadata-error.mir
new file mode 100644
index 0000000000000..e3ab673c4d127
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/X86/machine-metadata-error.mir
@@ -0,0 +1,25 @@
+# RUN: not llc -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# This test ensures that the MIR parser detects errors when parsing machine
+# metadata.
+--- |
+  target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+  target triple = "x86_64-unknown-linux-gnu"
+
+  define i32 @test_memcpy(i32* nocapture %p, i32* nocapture readonly %q) {
+    ret i32 0
+  }
+...
+---
+name:            test_memcpy
+machineMetadataNodes:
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!5 = !{!6}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+  - '!10 = !{!9}'
+body:             |
+  bb.0 (%ir-block.0):
+  ; CHECK: [[@LINE+1]]:96: use of undefined metadata '!11'
+    %2:gr64 = MOV64rm %0, 1, $noreg, 16, $noreg :: (load 8, align 4, !alias.scope !5, !noalias !11)
+
+...

diff  --git a/llvm/test/CodeGen/MIR/X86/machine-metadata.mir b/llvm/test/CodeGen/MIR/X86/machine-metadata.mir
new file mode 100644
index 0000000000000..b4993fcc59634
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/X86/machine-metadata.mir
@@ -0,0 +1,172 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=x86_64-linux-gnu -run-pass=none -o - %s | FileCheck %s
+--- |
+  ; ModuleID = 'test/CodeGen/X86/memcpy-scoped-aa.ll'
+  source_filename = "test/CodeGen/X86/memcpy-scoped-aa.ll"
+  target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+  target triple = "x86_64-unknown-linux-gnu"
+
+  define i32 @test_memcpy(i32* nocapture %p, i32* nocapture readonly %q) {
+    %p0 = bitcast i32* %p to i8*
+    %add.ptr = getelementptr inbounds i32, i32* %p, i64 4
+    %p1 = bitcast i32* %add.ptr to i8*
+    tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 4 dereferenceable(16) %p0, i8* noundef nonnull align 4 dereferenceable(16) %p1, i64 16, i1 false), !alias.scope !0, !noalias !3
+    %v0 = load i32, i32* %q, align 4, !alias.scope !3, !noalias !0
+    %q1 = getelementptr inbounds i32, i32* %q, i64 1
+    %v1 = load i32, i32* %q1, align 4, !alias.scope !3, !noalias !0
+    %add = add i32 %v0, %v1
+    ret i32 %add
+  }
+
+  define i32 @test_memcpy_inline(i32* nocapture %p, i32* nocapture readonly %q) {
+    %p0 = bitcast i32* %p to i8*
+    %add.ptr = getelementptr inbounds i32, i32* %p, i64 4
+    %p1 = bitcast i32* %add.ptr to i8*
+    tail call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* noundef nonnull align 4 dereferenceable(16) %p0, i8* noundef nonnull align 4 dereferenceable(16) %p1, i64 16, i1 false), !alias.scope !0, !noalias !3
+    %v0 = load i32, i32* %q, align 4, !alias.scope !3, !noalias !0
+    %q1 = getelementptr inbounds i32, i32* %q, i64 1
+    %v1 = load i32, i32* %q1, align 4, !alias.scope !3, !noalias !0
+    %add = add i32 %v0, %v1
+    ret i32 %add
+  }
+
+  define i32 @test_mempcpy(i32* nocapture %p, i32* nocapture readonly %q) {
+    %p0 = bitcast i32* %p to i8*
+    %add.ptr = getelementptr inbounds i32, i32* %p, i64 4
+    %p1 = bitcast i32* %add.ptr to i8*
+    %call = tail call i8* @mempcpy(i8* noundef nonnull align 4 dereferenceable(16) %p0, i8* noundef nonnull align 4 dereferenceable(16) %p1, i64 16), !alias.scope !0, !noalias !3
+    %v0 = load i32, i32* %q, align 4, !alias.scope !3, !noalias !0
+    %q1 = getelementptr inbounds i32, i32* %q, i64 1
+    %v1 = load i32, i32* %q1, align 4, !alias.scope !3, !noalias !0
+    %add = add i32 %v0, %v1
+    ret i32 %add
+  }
+
+  ; Function Attrs: argmemonly nofree nounwind willreturn
+  declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0
+
+  ; Function Attrs: argmemonly nofree nounwind willreturn
+  declare void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64 immarg, i1 immarg) #0
+
+  declare i8* @mempcpy(i8*, i8*, i64)
+
+  attributes #0 = { argmemonly nofree nounwind willreturn }
+
+  !0 = !{!1}
+  !1 = distinct !{!1, !2, !"bax: %p"}
+  !2 = distinct !{!2, !"bax"}
+  !3 = !{!4}
+  !4 = distinct !{!4, !2, !"bax: %q"}
+
+...
+---
+name:            test_memcpy
+machineMetadataNodes:
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!8 = !{!4, !9}'
+  - '!5 = !{!1, !6}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+  - '!11 = !{!4, !6}'
+  - '!10 = !{!1, !9}'
+body:             |
+  bb.0 (%ir-block.0):
+    liveins: $rdi, $rsi
+
+    ; CHECK-LABEL: name: test_memcpy
+    ; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rsi
+    ; CHECK: [[COPY1:%[0-9]+]]:gr64 = COPY $rdi
+    ; CHECK: [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm [[COPY1]], 1, $noreg, 16, $noreg :: (load 8 from %ir.p1, align 4, !alias.scope !5, !noalias !8)
+    ; CHECK: [[MOV64rm1:%[0-9]+]]:gr64 = MOV64rm [[COPY1]], 1, $noreg, 24, $noreg :: (load 8 from %ir.p1 + 8, align 4, !alias.scope !5, !noalias !8)
+    ; CHECK: MOV64mr [[COPY1]], 1, $noreg, 8, $noreg, killed [[MOV64rm1]] :: (store 8 into %ir.p0 + 8, align 4, !alias.scope !10, !noalias !11)
+    ; CHECK: MOV64mr [[COPY1]], 1, $noreg, 0, $noreg, killed [[MOV64rm]] :: (store 8 into %ir.p0, align 4, !alias.scope !10, !noalias !11)
+    ; CHECK: [[MOV32rm:%[0-9]+]]:gr32 = MOV32rm [[COPY]], 1, $noreg, 0, $noreg :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    ; CHECK: [[ADD32rm:%[0-9]+]]:gr32 = ADD32rm [[MOV32rm]], [[COPY]], 1, $noreg, 4, $noreg, implicit-def dead $eflags :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    ; CHECK: $eax = COPY [[ADD32rm]]
+    ; CHECK: RET 0, $eax
+    %1:gr64 = COPY $rsi
+    %0:gr64 = COPY $rdi
+    %2:gr64 = MOV64rm %0, 1, $noreg, 16, $noreg :: (load 8 from %ir.p1, align 4, !alias.scope !5, !noalias !8)
+    %3:gr64 = MOV64rm %0, 1, $noreg, 24, $noreg :: (load 8 from %ir.p1 + 8, align 4, !alias.scope !5, !noalias !8)
+    MOV64mr %0, 1, $noreg, 8, $noreg, killed %3 :: (store 8 into %ir.p0 + 8, align 4, !alias.scope !10, !noalias !11)
+    MOV64mr %0, 1, $noreg, 0, $noreg, killed %2 :: (store 8 into %ir.p0, align 4, !alias.scope !10, !noalias !11)
+    %4:gr32 = MOV32rm %1, 1, $noreg, 0, $noreg :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    %5:gr32 = ADD32rm %4, %1, 1, $noreg, 4, $noreg, implicit-def dead $eflags :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    $eax = COPY %5
+    RET 0, $eax
+
+...
+---
+name:            test_memcpy_inline
+machineMetadataNodes:
+  - '!8 = !{!4, !9}'
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+  - '!5 = !{!1, !6}'
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+  - '!11 = !{!4, !6}'
+  - '!10 = !{!1, !9}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+body:             |
+  bb.0 (%ir-block.0):
+    liveins: $rdi, $rsi
+
+    ; CHECK-LABEL: name: test_memcpy_inline
+    ; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rsi
+    ; CHECK: [[COPY1:%[0-9]+]]:gr64 = COPY $rdi
+    ; CHECK: [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm [[COPY1]], 1, $noreg, 16, $noreg :: (load 8 from %ir.p1, align 4, !alias.scope !5, !noalias !8)
+    ; CHECK: [[MOV64rm1:%[0-9]+]]:gr64 = MOV64rm [[COPY1]], 1, $noreg, 24, $noreg :: (load 8 from %ir.p1 + 8, align 4, !alias.scope !5, !noalias !8)
+    ; CHECK: MOV64mr [[COPY1]], 1, $noreg, 8, $noreg, killed [[MOV64rm1]] :: (store 8 into %ir.p0 + 8, align 4, !alias.scope !10, !noalias !11)
+    ; CHECK: MOV64mr [[COPY1]], 1, $noreg, 0, $noreg, killed [[MOV64rm]] :: (store 8 into %ir.p0, align 4, !alias.scope !10, !noalias !11)
+    ; CHECK: [[MOV32rm:%[0-9]+]]:gr32 = MOV32rm [[COPY]], 1, $noreg, 0, $noreg :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    ; CHECK: [[ADD32rm:%[0-9]+]]:gr32 = ADD32rm [[MOV32rm]], [[COPY]], 1, $noreg, 4, $noreg, implicit-def dead $eflags :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    ; CHECK: $eax = COPY [[ADD32rm]]
+    ; CHECK: RET 0, $eax
+    %1:gr64 = COPY $rsi
+    %0:gr64 = COPY $rdi
+    %2:gr64 = MOV64rm %0, 1, $noreg, 16, $noreg :: (load 8 from %ir.p1, align 4, !alias.scope !5, !noalias !8)
+    %3:gr64 = MOV64rm %0, 1, $noreg, 24, $noreg :: (load 8 from %ir.p1 + 8, align 4, !alias.scope !5, !noalias !8)
+    MOV64mr %0, 1, $noreg, 8, $noreg, killed %3 :: (store 8 into %ir.p0 + 8, align 4, !alias.scope !10, !noalias !11)
+    MOV64mr %0, 1, $noreg, 0, $noreg, killed %2 :: (store 8 into %ir.p0, align 4, !alias.scope !10, !noalias !11)
+    %4:gr32 = MOV32rm %1, 1, $noreg, 0, $noreg :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    %5:gr32 = ADD32rm %4, %1, 1, $noreg, 4, $noreg, implicit-def dead $eflags :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    $eax = COPY %5
+    RET 0, $eax
+
+...
+---
+name:            test_mempcpy
+machineMetadataNodes:
+  - '!5 = !{!1, !6}'
+  - '!8 = !{!4, !9}'
+  - '!11 = !{!4, !6}'
+  - '!10 = !{!1, !9}'
+  - '!7 = distinct !{!7, !"MemcpyLoweringDomain"}'
+  - '!6 = distinct !{!6, !7, !"Src"}'
+  - '!9 = distinct !{!9, !7, !"Dst"}'
+body:             |
+  bb.0 (%ir-block.0):
+    liveins: $rdi, $rsi
+
+    ; CHECK-LABEL: name: test_mempcpy
+    ; CHECK: [[COPY:%[0-9]+]]:gr64 = COPY $rsi
+    ; CHECK: [[COPY1:%[0-9]+]]:gr64 = COPY $rdi
+    ; CHECK: [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm [[COPY1]], 1, $noreg, 16, $noreg :: (load 8 from %ir.p1, align 1, !alias.scope !5, !noalias !8)
+    ; CHECK: [[MOV64rm1:%[0-9]+]]:gr64 = MOV64rm [[COPY1]], 1, $noreg, 24, $noreg :: (load 8 from %ir.p1 + 8, align 1, !alias.scope !5, !noalias !8)
+    ; CHECK: MOV64mr [[COPY1]], 1, $noreg, 8, $noreg, killed [[MOV64rm1]] :: (store 8 into %ir.p0 + 8, align 1, !alias.scope !10, !noalias !11)
+    ; CHECK: MOV64mr [[COPY1]], 1, $noreg, 0, $noreg, killed [[MOV64rm]] :: (store 8 into %ir.p0, align 1, !alias.scope !10, !noalias !11)
+    ; CHECK: [[MOV32rm:%[0-9]+]]:gr32 = MOV32rm [[COPY]], 1, $noreg, 0, $noreg :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    ; CHECK: [[ADD32rm:%[0-9]+]]:gr32 = ADD32rm [[MOV32rm]], [[COPY]], 1, $noreg, 4, $noreg, implicit-def dead $eflags :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    ; CHECK: $eax = COPY [[ADD32rm]]
+    ; CHECK: RET 0, $eax
+    %1:gr64 = COPY $rsi
+    %0:gr64 = COPY $rdi
+    %2:gr64 = MOV64rm %0, 1, $noreg, 16, $noreg :: (load 8 from %ir.p1, align 1, !alias.scope !5, !noalias !8)
+    %3:gr64 = MOV64rm %0, 1, $noreg, 24, $noreg :: (load 8 from %ir.p1 + 8, align 1, !alias.scope !5, !noalias !8)
+    MOV64mr %0, 1, $noreg, 8, $noreg, killed %3 :: (store 8 into %ir.p0 + 8, align 1, !alias.scope !10, !noalias !11)
+    MOV64mr %0, 1, $noreg, 0, $noreg, killed %2 :: (store 8 into %ir.p0, align 1, !alias.scope !10, !noalias !11)
+    %4:gr32 = MOV32rm %1, 1, $noreg, 0, $noreg :: (load 4 from %ir.q, !alias.scope !3, !noalias !0)
+    %5:gr32 = ADD32rm %4, %1, 1, $noreg, 4, $noreg, implicit-def dead $eflags :: (load 4 from %ir.q1, !alias.scope !3, !noalias !0)
+    $eax = COPY %5
+    RET 0, $eax
+
+...


        


More information about the llvm-commits mailing list