xref: /llvm-project/llvm/unittests/MIR/MachineMetadata.cpp (revision b6a01caa64aaac2e5db8d7953a81cbe1a139b81f)
1 //===- MachineInstrBundleIteratorTest.cpp ---------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/ADT/STLExtras.h"
10 #include "llvm/CodeGen/MIRParser/MIRParser.h"
11 #include "llvm/CodeGen/MIRPrinter.h"
12 #include "llvm/CodeGen/MachineFunction.h"
13 #include "llvm/CodeGen/MachineMemOperand.h"
14 #include "llvm/CodeGen/MachineModuleInfo.h"
15 #include "llvm/CodeGen/MachineModuleSlotTracker.h"
16 #include "llvm/CodeGen/MachineOperand.h"
17 #include "llvm/CodeGen/TargetFrameLowering.h"
18 #include "llvm/CodeGen/TargetInstrInfo.h"
19 #include "llvm/CodeGen/TargetLowering.h"
20 #include "llvm/CodeGen/TargetSubtargetInfo.h"
21 #include "llvm/FileCheck/FileCheck.h"
22 #include "llvm/IR/MDBuilder.h"
23 #include "llvm/IR/ModuleSlotTracker.h"
24 #include "llvm/MC/MCAsmInfo.h"
25 #include "llvm/MC/TargetRegistry.h"
26 #include "llvm/Support/SourceMgr.h"
27 #include "llvm/Support/TargetSelect.h"
28 #include "llvm/Target/TargetMachine.h"
29 #include "gtest/gtest.h"
30 
31 using namespace llvm;
32 
33 class MachineMetadataTest : public testing::Test {
34 public:
35   MachineMetadataTest() {}
36 
37 protected:
38   LLVMContext Context;
39   std::unique_ptr<Module> M;
40   std::unique_ptr<MIRParser> MIR;
41 
42   static void SetUpTestCase() {
43     InitializeAllTargetInfos();
44     InitializeAllTargets();
45     InitializeAllTargetMCs();
46   }
47 
48   void SetUp() override { M = std::make_unique<Module>("Dummy", Context); }
49 
50   void addHooks(ModuleSlotTracker &MST, const MachineOperand &MO) {
51     // Setup hooks to assign slot numbers for the specified machine metadata.
52     MST.setProcessHook([&MO](AbstractSlotTrackerStorage *AST, const Module *M,
53                              bool ShouldInitializeAllMetadata) {
54       if (ShouldInitializeAllMetadata) {
55         if (MO.isMetadata())
56           AST->createMetadataSlot(MO.getMetadata());
57       }
58     });
59     MST.setProcessHook([&MO](AbstractSlotTrackerStorage *AST, const Function *F,
60                              bool ShouldInitializeAllMetadata) {
61       if (!ShouldInitializeAllMetadata) {
62         if (MO.isMetadata())
63           AST->createMetadataSlot(MO.getMetadata());
64       }
65     });
66   }
67 
68   std::unique_ptr<LLVMTargetMachine>
69   createTargetMachine(std::string TT, StringRef CPU, StringRef FS) {
70     std::string Error;
71     const Target *T = TargetRegistry::lookupTarget(TT, Error);
72     if (!T)
73       return nullptr;
74     TargetOptions Options;
75     return std::unique_ptr<LLVMTargetMachine>(
76         static_cast<LLVMTargetMachine *>(T->createTargetMachine(
77             TT, CPU, FS, Options, std::nullopt, std::nullopt)));
78   }
79 
80   std::unique_ptr<Module> parseMIR(const TargetMachine &TM, StringRef MIRCode,
81                                    const char *FnName, MachineModuleInfo &MMI) {
82     SMDiagnostic Diagnostic;
83     std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
84     MIR = createMIRParser(std::move(MBuffer), Context);
85     if (!MIR)
86       return nullptr;
87 
88     std::unique_ptr<Module> Mod = MIR->parseIRModule();
89     if (!Mod)
90       return nullptr;
91 
92     Mod->setDataLayout(TM.createDataLayout());
93 
94     if (MIR->parseMachineFunctions(*Mod, MMI)) {
95       M.reset();
96       return nullptr;
97     }
98 
99     return Mod;
100   }
101 };
102 
103 // Helper to dump the printer output into a string.
104 static std::string print(std::function<void(raw_ostream &OS)> PrintFn) {
105   std::string Str;
106   raw_string_ostream OS(Str);
107   PrintFn(OS);
108   OS.flush();
109   return Str;
110 }
111 
112 TEST_F(MachineMetadataTest, TrivialHook) {
113   // Verify that post-process hook is invoked to assign slot numbers for
114   // machine metadata.
115   ASSERT_TRUE(M);
116 
117   // Create a MachineOperand with a metadata and print it.
118   Metadata *MDS = MDString::get(Context, "foo");
119   MDNode *Node = MDNode::get(Context, MDS);
120   MachineOperand MO = MachineOperand::CreateMetadata(Node);
121 
122   // Checking some preconditions on the newly created
123   // MachineOperand.
124   ASSERT_TRUE(MO.isMetadata());
125   ASSERT_EQ(MO.getMetadata(), Node);
126 
127   ModuleSlotTracker MST(M.get());
128   addHooks(MST, MO);
129 
130   // Print a MachineOperand containing a metadata node.
131   EXPECT_EQ("!0", print([&](raw_ostream &OS) {
132               MO.print(OS, MST, LLT{}, /*OpIdx*/ ~0U, /*PrintDef=*/false,
133                        /*IsStandalone=*/false,
134                        /*ShouldPrintRegisterTies=*/false, /*TiedOperandIdx=*/0,
135                        /*TRI=*/nullptr,
136                        /*IntrinsicInfo=*/nullptr);
137             }));
138   // Print the definition of that metadata node.
139   EXPECT_EQ("!0 = !{!\"foo\"}",
140             print([&](raw_ostream &OS) { Node->print(OS, MST); }));
141 }
142 
143 TEST_F(MachineMetadataTest, BasicHook) {
144   // Verify that post-process hook is invoked to assign slot numbers for
145   // machine metadata. When both LLVM IR and machine IR contain metadata,
146   // ensure that machine metadata is always assigned after LLVM IR.
147   ASSERT_TRUE(M);
148 
149   // Create a MachineOperand with a metadata and print it.
150   Metadata *MachineMDS = MDString::get(Context, "foo");
151   MDNode *MachineNode = MDNode::get(Context, MachineMDS);
152   MachineOperand MO = MachineOperand::CreateMetadata(MachineNode);
153 
154   // Checking some preconditions on the newly created
155   // MachineOperand.
156   ASSERT_TRUE(MO.isMetadata());
157   ASSERT_EQ(MO.getMetadata(), MachineNode);
158 
159   // Create metadata in LLVM IR.
160   NamedMDNode *MD = M->getOrInsertNamedMetadata("namedmd");
161   Metadata *MDS = MDString::get(Context, "bar");
162   MDNode *Node = MDNode::get(Context, MDS);
163   MD->addOperand(Node);
164 
165   ModuleSlotTracker MST(M.get());
166   addHooks(MST, MO);
167 
168   // Print a MachineOperand containing a metadata node.
169   EXPECT_EQ("!1", print([&](raw_ostream &OS) {
170               MO.print(OS, MST, LLT{}, /*OpIdx*/ ~0U, /*PrintDef=*/false,
171                        /*IsStandalone=*/false,
172                        /*ShouldPrintRegisterTies=*/false, /*TiedOperandIdx=*/0,
173                        /*TRI=*/nullptr,
174                        /*IntrinsicInfo=*/nullptr);
175             }));
176   // Print the definition of these unnamed metadata nodes.
177   EXPECT_EQ("!0 = !{!\"bar\"}",
178             print([&](raw_ostream &OS) { Node->print(OS, MST); }));
179   EXPECT_EQ("!1 = !{!\"foo\"}",
180             print([&](raw_ostream &OS) { MachineNode->print(OS, MST); }));
181 }
182 
183 static bool checkOutput(std::string CheckString, std::string Output) {
184   auto CheckBuffer = MemoryBuffer::getMemBuffer(CheckString, "");
185   auto OutputBuffer = MemoryBuffer::getMemBuffer(Output, "Output", false);
186 
187   SmallString<4096> CheckFileBuffer;
188   FileCheckRequest Req;
189   FileCheck FC(Req);
190   StringRef CheckFileText =
191       FC.CanonicalizeFile(*CheckBuffer.get(), CheckFileBuffer);
192 
193   SourceMgr SM;
194   SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(CheckFileText, "CheckFile"),
195                         SMLoc());
196   Regex PrefixRE = FC.buildCheckPrefixRegex();
197   if (FC.readCheckFile(SM, CheckFileText, PrefixRE))
198     return false;
199 
200   auto OutBuffer = OutputBuffer->getBuffer();
201   SM.AddNewSourceBuffer(std::move(OutputBuffer), SMLoc());
202   return FC.checkInput(SM, OutBuffer);
203 }
204 
205 TEST_F(MachineMetadataTest, MMSlotTrackerAArch64) {
206   auto TM = createTargetMachine(Triple::normalize("aarch64--"), "", "");
207   if (!TM)
208     GTEST_SKIP();
209 
210   StringRef MIRString = R"MIR(
211 --- |
212   define i32 @test0(i32* %p) {
213     %r = load i32, i32* %p, align 4
214     ret i32 %r
215   }
216 ...
217 ---
218 name:            test0
219 liveins:
220   - { reg: '$x0', virtual-reg: '%0' }
221 body:             |
222   bb.0 (%ir-block.0):
223     liveins: $x0
224 
225   %0:gpr64common = COPY $x0
226   %1:gpr32 = LDRWui %0, 0 :: (load (s32) from %ir.p)
227 ...
228 )MIR";
229 
230   MachineModuleInfo MMI(TM.get());
231   M = parseMIR(*TM, MIRString, "test0", MMI);
232   ASSERT_TRUE(M);
233 
234   auto *MF = MMI.getMachineFunction(*M->getFunction("test0"));
235   auto *MBB = MF->getBlockNumbered(0);
236 
237   auto &MI = MBB->back();
238   ASSERT_TRUE(MI.hasOneMemOperand());
239 
240   // Create and attached scoped AA metadata on that instruction with one MMO.
241   MDBuilder MDB(Context);
242   MDNode *Domain = MDB.createAnonymousAliasScopeDomain("domain");
243   MDNode *Scope0 = MDB.createAnonymousAliasScope(Domain, "scope0");
244   MDNode *Scope1 = MDB.createAnonymousAliasScope(Domain, "scope1");
245   MDNode *Set0 = MDNode::get(Context, {Scope0});
246   MDNode *Set1 = MDNode::get(Context, {Scope1});
247 
248   AAMDNodes AAInfo;
249   AAInfo.TBAA = AAInfo.TBAAStruct = nullptr;
250   AAInfo.Scope = Set0;
251   AAInfo.NoAlias = Set1;
252 
253   auto *OldMMO = MI.memoperands().front();
254   auto *NewMMO = MF->getMachineMemOperand(OldMMO, AAInfo);
255   MI.setMemRefs(*MF, NewMMO);
256 
257   MachineModuleSlotTracker MST(MF);
258   // Print that MI with new machine metadata, which slot numbers should be
259   // assigned.
260   EXPECT_EQ("%1:gpr32 = LDRWui %0, 0 :: (load (s32) from %ir.p, "
261             "!alias.scope !0, !noalias !3)",
262             print([&](raw_ostream &OS) {
263               MI.print(OS, MST, /*IsStandalone=*/false, /*SkipOpers=*/false,
264                        /*SkipDebugLoc=*/false, /*AddNewLine=*/false);
265             }));
266 
267   std::vector<const MDNode *> Generated{Domain, Scope0, Scope1, Set0, Set1};
268   // Examine machine metadata collected. They should match ones
269   // afore-generated.
270   std::vector<const MDNode *> Collected;
271   MachineModuleSlotTracker::MachineMDNodeListType MDList;
272   MST.collectMachineMDNodes(MDList);
273   for (auto &MD : MDList)
274     Collected.push_back(MD.second);
275 
276   llvm::sort(Generated);
277   llvm::sort(Collected);
278   EXPECT_EQ(Collected, Generated);
279 
280   // FileCheck the output from MIR printer.
281   std::string Output = print([&](raw_ostream &OS) { printMIR(OS, *MF); });
282   std::string CheckString = R"(
283 CHECK: machineMetadataNodes:
284 CHECK-DAG: ![[MMDOMAIN:[0-9]+]] = distinct !{!{{[0-9]+}}, !"domain"}
285 CHECK-DAG: ![[MMSCOPE0:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope0"}
286 CHECK-DAG: ![[MMSCOPE1:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope1"}
287 CHECK-DAG: ![[MMSET0:[0-9]+]] = !{![[MMSCOPE0]]}
288 CHECK-DAG: ![[MMSET1:[0-9]+]] = !{![[MMSCOPE1]]}
289 CHECK: body:
290 CHECK: %1:gpr32 = LDRWui %0, 0 :: (load (s32) from %ir.p, !alias.scope ![[MMSET0]], !noalias ![[MMSET1]])
291 )";
292   EXPECT_TRUE(checkOutput(CheckString, Output));
293 }
294 
295 TEST_F(MachineMetadataTest, isMetaInstruction) {
296   auto TM = createTargetMachine(Triple::normalize("x86_64--"), "", "");
297   if (!TM)
298     GTEST_SKIP();
299 
300   StringRef MIRString = R"MIR(
301 --- |
302   define void @test0(i32 %b) {
303     ret void
304   }
305   !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
306   !1 = !DIFile(filename: "a.c", directory: "/tmp")
307   !2 = !{i32 7, !"Dwarf Version", i32 4}
308   !3 = !{i32 2, !"Debug Info Version", i32 3}
309   !4 = !{i32 1, !"wchar_size", i32 4}
310   !5 = !{i32 7, !"uwtable", i32 1}
311   !6 = !{i32 7, !"frame-pointer", i32 2}
312   !7 = !{!""}
313   !8 = distinct !DISubprogram(name: "test0", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !12)
314   !9 = !DISubroutineType(types: !10)
315   !10 = !{null, !11}
316   !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
317   !12 = !{}
318   !13 = !DILocalVariable(name: "b", arg: 1, scope: !8, file: !1, line: 1, type: !11)
319   !14 = !DILocation(line: 1, column: 16, scope: !8)
320 ...
321 ---
322 name:            test0
323 machineFunctionInfo
324 body:             |
325   bb.0:
326   $rdi = IMPLICIT_DEF
327   KILL $rsi
328   CFI_INSTRUCTION undefined $rax
329   EH_LABEL 0
330   GC_LABEL 0
331   DBG_VALUE $rax, $noreg, !13, !DIExpression(), debug-location !14
332   DBG_LABEL 0
333   LIFETIME_START 0
334   LIFETIME_END 0
335   PSEUDO_PROBE 6699318081062747564, 1, 0, 0
336   $xmm0 = ARITH_FENCE $xmm0
337   Int_MemBarrier
338 ...
339 )MIR";
340 
341   MachineModuleInfo MMI(TM.get());
342   M = parseMIR(*TM, MIRString, "test0", MMI);
343   ASSERT_TRUE(M);
344 
345   auto *MF = MMI.getMachineFunction(*M->getFunction("test0"));
346   auto *MBB = MF->getBlockNumbered(0);
347 
348   for (auto It = MBB->begin(); It != MBB->end(); ++It) {
349     MachineInstr &MI = *It;
350     ASSERT_TRUE(MI.isMetaInstruction());
351   }
352 }
353 
354 TEST_F(MachineMetadataTest, MMSlotTrackerX64) {
355   auto TM = createTargetMachine(Triple::normalize("x86_64--"), "", "");
356   if (!TM)
357     GTEST_SKIP();
358 
359   StringRef MIRString = R"MIR(
360 --- |
361   define i32 @test0(i32* %p) {
362     %r = load i32, i32* %p, align 4
363     ret i32 %r
364   }
365 ...
366 ---
367 name:            test0
368 liveins:
369   - { reg: '$rdi', virtual-reg: '%0' }
370 body:             |
371   bb.0 (%ir-block.0):
372     liveins: $rdi
373 
374   %0:gr64 = COPY $rdi
375   %1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load (s32) from %ir.p)
376 ...
377 )MIR";
378 
379   MachineModuleInfo MMI(TM.get());
380   M = parseMIR(*TM, MIRString, "test0", MMI);
381   ASSERT_TRUE(M);
382 
383   auto *MF = MMI.getMachineFunction(*M->getFunction("test0"));
384   auto *MBB = MF->getBlockNumbered(0);
385 
386   auto &MI = MBB->back();
387   ASSERT_FALSE(MI.memoperands_empty());
388   ASSERT_TRUE(MI.hasOneMemOperand());
389 
390   // Create and attached scoped AA metadata on that instruction with one MMO.
391   MDBuilder MDB(Context);
392   MDNode *Domain = MDB.createAnonymousAliasScopeDomain("domain");
393   MDNode *Scope0 = MDB.createAnonymousAliasScope(Domain, "scope0");
394   MDNode *Scope1 = MDB.createAnonymousAliasScope(Domain, "scope1");
395   MDNode *Set0 = MDNode::get(Context, {Scope0});
396   MDNode *Set1 = MDNode::get(Context, {Scope1});
397 
398   AAMDNodes AAInfo;
399   AAInfo.TBAA = AAInfo.TBAAStruct = nullptr;
400   AAInfo.Scope = Set0;
401   AAInfo.NoAlias = Set1;
402 
403   auto *OldMMO = MI.memoperands().front();
404   auto *NewMMO = MF->getMachineMemOperand(OldMMO, AAInfo);
405   MI.setMemRefs(*MF, NewMMO);
406 
407   MachineModuleSlotTracker MST(MF);
408   // Print that MI with new machine metadata, which slot numbers should be
409   // assigned.
410   EXPECT_EQ("%1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load (s32) from %ir.p, "
411             "!alias.scope !0, !noalias !3)",
412             print([&](raw_ostream &OS) {
413               MI.print(OS, MST, /*IsStandalone=*/false, /*SkipOpers=*/false,
414                        /*SkipDebugLoc=*/false, /*AddNewLine=*/false);
415             }));
416 
417   std::vector<const MDNode *> Generated{Domain, Scope0, Scope1, Set0, Set1};
418   // Examine machine metadata collected. They should match ones
419   // afore-generated.
420   std::vector<const MDNode *> Collected;
421   MachineModuleSlotTracker::MachineMDNodeListType MDList;
422   MST.collectMachineMDNodes(MDList);
423   for (auto &MD : MDList)
424     Collected.push_back(MD.second);
425 
426   llvm::sort(Generated);
427   llvm::sort(Collected);
428   EXPECT_EQ(Collected, Generated);
429 
430   // FileCheck the output from MIR printer.
431   std::string Output = print([&](raw_ostream &OS) { printMIR(OS, *MF); });
432   std::string CheckString = R"(
433 CHECK: machineMetadataNodes:
434 CHECK-DAG: ![[MMDOMAIN:[0-9]+]] = distinct !{!{{[0-9]+}}, !"domain"}
435 CHECK-DAG: ![[MMSCOPE0:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope0"}
436 CHECK-DAG: ![[MMSCOPE1:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope1"}
437 CHECK-DAG: ![[MMSET0:[0-9]+]] = !{![[MMSCOPE0]]}
438 CHECK-DAG: ![[MMSET1:[0-9]+]] = !{![[MMSCOPE1]]}
439 CHECK: body:
440 CHECK: %1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load (s32) from %ir.p, !alias.scope ![[MMSET0]], !noalias ![[MMSET1]])
441 )";
442   EXPECT_TRUE(checkOutput(CheckString, Output));
443 }
444 
445 TEST_F(MachineMetadataTest, MMSlotTrackerAMDGPU) {
446   auto TM = createTargetMachine(Triple::normalize("amdgcn-amd-amdhsa"),
447                                 "gfx1010", "");
448   if (!TM)
449     GTEST_SKIP();
450 
451   StringRef MIRString = R"MIR(
452 --- |
453   define i32 @test0(i32* %p) {
454     %r = load i32, i32* %p, align 4
455     ret i32 %r
456   }
457 ...
458 ---
459 name:            test0
460 liveins:
461   - { reg: '$vgpr0', virtual-reg: '%0' }
462   - { reg: '$vgpr1', virtual-reg: '%1' }
463   - { reg: '$sgpr30_sgpr31', virtual-reg: '%2' }
464 body:             |
465   bb.0 (%ir-block.0):
466     liveins: $vgpr0, $vgpr1, $sgpr30_sgpr31
467 
468     %2:sreg_64 = COPY $sgpr30_sgpr31
469     %1:vgpr_32 = COPY $vgpr1
470     %0:vgpr_32 = COPY $vgpr0
471     %8:vreg_64 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1
472     %6:vreg_64 = COPY %8
473     %5:vgpr_32 = FLAT_LOAD_DWORD killed %6, 0, 0, implicit $exec, implicit $flat_scr :: (load (s32) from %ir.p)
474 ...
475 )MIR";
476 
477   MachineModuleInfo MMI(TM.get());
478   M = parseMIR(*TM, MIRString, "test0", MMI);
479   ASSERT_TRUE(M);
480 
481   auto *MF = MMI.getMachineFunction(*M->getFunction("test0"));
482   auto *MBB = MF->getBlockNumbered(0);
483 
484   auto &MI = MBB->back();
485   ASSERT_FALSE(MI.memoperands_empty());
486   ASSERT_TRUE(MI.hasOneMemOperand());
487 
488   // Create and attached scoped AA metadata on that instruction with one MMO.
489   MDBuilder MDB(Context);
490   MDNode *Domain = MDB.createAnonymousAliasScopeDomain("domain");
491   MDNode *Scope0 = MDB.createAnonymousAliasScope(Domain, "scope0");
492   MDNode *Scope1 = MDB.createAnonymousAliasScope(Domain, "scope1");
493   MDNode *Set0 = MDNode::get(Context, {Scope0});
494   MDNode *Set1 = MDNode::get(Context, {Scope1});
495 
496   AAMDNodes AAInfo;
497   AAInfo.TBAA = AAInfo.TBAAStruct = nullptr;
498   AAInfo.Scope = Set0;
499   AAInfo.NoAlias = Set1;
500 
501   auto *OldMMO = MI.memoperands().front();
502   auto *NewMMO = MF->getMachineMemOperand(OldMMO, AAInfo);
503   MI.setMemRefs(*MF, NewMMO);
504 
505   MachineModuleSlotTracker MST(MF);
506   // Print that MI with new machine metadata, which slot numbers should be
507   // assigned.
508   EXPECT_EQ(
509       "%5:vgpr_32 = FLAT_LOAD_DWORD killed %4, 0, 0, implicit $exec, implicit "
510       "$flat_scr :: (load (s32) from %ir.p, !alias.scope !0, !noalias !3)",
511       print([&](raw_ostream &OS) {
512         MI.print(OS, MST, /*IsStandalone=*/false, /*SkipOpers=*/false,
513                  /*SkipDebugLoc=*/false, /*AddNewLine=*/false);
514       }));
515 
516   std::vector<const MDNode *> Generated{Domain, Scope0, Scope1, Set0, Set1};
517   // Examine machine metadata collected. They should match ones
518   // afore-generated.
519   std::vector<const MDNode *> Collected;
520   MachineModuleSlotTracker::MachineMDNodeListType MDList;
521   MST.collectMachineMDNodes(MDList);
522   for (auto &MD : MDList)
523     Collected.push_back(MD.second);
524 
525   llvm::sort(Generated);
526   llvm::sort(Collected);
527   EXPECT_EQ(Collected, Generated);
528 
529   // FileCheck the output from MIR printer.
530   std::string Output = print([&](raw_ostream &OS) { printMIR(OS, *MF); });
531   std::string CheckString = R"(
532 CHECK: machineMetadataNodes:
533 CHECK-DAG: ![[MMDOMAIN:[0-9]+]] = distinct !{!{{[0-9]+}}, !"domain"}
534 CHECK-DAG: ![[MMSCOPE0:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope0"}
535 CHECK-DAG: ![[MMSCOPE1:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope1"}
536 CHECK-DAG: ![[MMSET0:[0-9]+]] = !{![[MMSCOPE0]]}
537 CHECK-DAG: ![[MMSET1:[0-9]+]] = !{![[MMSCOPE1]]}
538 CHECK: body:
539 CHECK: %5:vgpr_32 = FLAT_LOAD_DWORD killed %4, 0, 0, implicit $exec, implicit $flat_scr :: (load (s32) from %ir.p, !alias.scope ![[MMSET0]], !noalias ![[MMSET1]])
540 )";
541   EXPECT_TRUE(checkOutput(CheckString, Output));
542 }
543 
544 TEST_F(MachineMetadataTest, TiedOpsRewritten) {
545   auto TM = createTargetMachine(Triple::normalize("powerpc64--"), "", "");
546   if (!TM)
547     GTEST_SKIP();
548   StringRef MIRString = R"MIR(
549 ---
550 name:            foo
551 alignment:       16
552 tracksRegLiveness: true
553 frameInfo:
554   maxAlignment:    16
555 machineFunctionInfo: {}
556 body:             |
557   bb.0:
558     liveins: $r3
559     %0:gprc = COPY $r3
560     %0 = RLWIMI killed %0, $r3, 1, 0, 30
561     $r3 = COPY %0
562     BLR8 implicit $r3, implicit $lr8, implicit $rm
563 
564 ...
565 )MIR";
566   MachineModuleInfo MMI(TM.get());
567   M = parseMIR(*TM, MIRString, "foo", MMI);
568   ASSERT_TRUE(M);
569   auto *MF = MMI.getMachineFunction(*M->getFunction("foo"));
570   MachineFunctionProperties &Properties = MF->getProperties();
571   ASSERT_TRUE(Properties.hasProperty(
572       MachineFunctionProperties::Property::TiedOpsRewritten));
573 }
574 
575 TEST_F(MachineMetadataTest, NoTiedOpsRewritten) {
576   auto TM = createTargetMachine(Triple::normalize("powerpc64--"), "", "");
577   if (!TM)
578     GTEST_SKIP();
579   StringRef MIRString = R"MIR(
580 ---
581 name:            foo
582 alignment:       16
583 tracksRegLiveness: true
584 frameInfo:
585   maxAlignment:    16
586 machineFunctionInfo: {}
587 body:             |
588   bb.0:
589     liveins: $r3
590     %0:gprc = COPY $r3
591     %1:gprc = RLWIMI killed %0, $r3, 1, 0, 30
592     $r3 = COPY %1
593     BLR8 implicit $r3, implicit $lr8, implicit $rm
594 
595 ...
596 )MIR";
597   MachineModuleInfo MMI(TM.get());
598   M = parseMIR(*TM, MIRString, "foo", MMI);
599   ASSERT_TRUE(M);
600   auto *MF = MMI.getMachineFunction(*M->getFunction("foo"));
601   MachineFunctionProperties &Properties = MF->getProperties();
602   ASSERT_FALSE(Properties.hasProperty(
603       MachineFunctionProperties::Property::TiedOpsRewritten));
604 }
605