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>(args: "Dummy" , args&: 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(Triple: 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, Features: FS, Options, RM: std::nullopt, CM: 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(InputData: MIRCode); |
84 | MIR = createMIRParser(Contents: 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(M&: *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, Str: "foo" ); |
119 | MDNode *Node = MDNode::get(Context, MDs: MDS); |
120 | MachineOperand MO = MachineOperand::CreateMetadata(Meta: 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, Str: "foo" ); |
151 | MDNode *MachineNode = MDNode::get(Context, MDs: MachineMDS); |
152 | MachineOperand MO = MachineOperand::CreateMetadata(Meta: 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(Name: "namedmd" ); |
161 | Metadata *MDS = MDString::get(Context, Str: "bar" ); |
162 | MDNode *Node = MDNode::get(Context, MDs: MDS); |
163 | MD->addOperand(M: 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(InputData: CheckString, BufferName: "" ); |
185 | auto OutputBuffer = MemoryBuffer::getMemBuffer(InputData: Output, BufferName: "Output" , RequiresNullTerminator: false); |
186 | |
187 | SmallString<4096> CheckFileBuffer; |
188 | FileCheckRequest Req; |
189 | FileCheck FC(Req); |
190 | StringRef CheckFileText = |
191 | FC.CanonicalizeFile(MB&: *CheckBuffer.get(), OutputBuffer&: CheckFileBuffer); |
192 | |
193 | SourceMgr SM; |
194 | SM.AddNewSourceBuffer(F: MemoryBuffer::getMemBuffer(InputData: CheckFileText, BufferName: "CheckFile" ), |
195 | IncludeLoc: SMLoc()); |
196 | if (FC.readCheckFile(SM, Buffer: CheckFileText)) |
197 | return false; |
198 | |
199 | auto OutBuffer = OutputBuffer->getBuffer(); |
200 | SM.AddNewSourceBuffer(F: std::move(OutputBuffer), IncludeLoc: SMLoc()); |
201 | return FC.checkInput(SM, Buffer: OutBuffer); |
202 | } |
203 | |
204 | TEST_F(MachineMetadataTest, MMSlotTrackerAArch64) { |
205 | auto TM = createTargetMachine(TT: Triple::normalize(Str: "aarch64--" ), CPU: "" , FS: "" ); |
206 | if (!TM) |
207 | GTEST_SKIP(); |
208 | |
209 | StringRef MIRString = R"MIR( |
210 | --- | |
211 | define i32 @test0(i32* %p) { |
212 | %r = load i32, i32* %p, align 4 |
213 | ret i32 %r |
214 | } |
215 | ... |
216 | --- |
217 | name: test0 |
218 | liveins: |
219 | - { reg: '$x0', virtual-reg: '%0' } |
220 | body: | |
221 | bb.0 (%ir-block.0): |
222 | liveins: $x0 |
223 | |
224 | %0:gpr64common = COPY $x0 |
225 | %1:gpr32 = LDRWui %0, 0 :: (load (s32) from %ir.p) |
226 | ... |
227 | )MIR" ; |
228 | |
229 | MachineModuleInfo MMI(TM.get()); |
230 | M = parseMIR(TM: *TM, MIRCode: MIRString, FnName: "test0" , MMI); |
231 | ASSERT_TRUE(M); |
232 | |
233 | auto *MF = MMI.getMachineFunction(F: *M->getFunction(Name: "test0" )); |
234 | auto *MBB = MF->getBlockNumbered(N: 0); |
235 | |
236 | auto &MI = MBB->back(); |
237 | ASSERT_TRUE(MI.hasOneMemOperand()); |
238 | |
239 | // Create and attached scoped AA metadata on that instruction with one MMO. |
240 | MDBuilder MDB(Context); |
241 | MDNode *Domain = MDB.createAnonymousAliasScopeDomain(Name: "domain" ); |
242 | MDNode *Scope0 = MDB.createAnonymousAliasScope(Domain, Name: "scope0" ); |
243 | MDNode *Scope1 = MDB.createAnonymousAliasScope(Domain, Name: "scope1" ); |
244 | MDNode *Set0 = MDNode::get(Context, MDs: {Scope0}); |
245 | MDNode *Set1 = MDNode::get(Context, MDs: {Scope1}); |
246 | |
247 | AAMDNodes AAInfo; |
248 | AAInfo.TBAA = AAInfo.TBAAStruct = nullptr; |
249 | AAInfo.Scope = Set0; |
250 | AAInfo.NoAlias = Set1; |
251 | |
252 | auto *OldMMO = MI.memoperands().front(); |
253 | auto *NewMMO = MF->getMachineMemOperand(MMO: OldMMO, AAInfo); |
254 | MI.setMemRefs(MF&: *MF, MemRefs: NewMMO); |
255 | |
256 | MachineModuleSlotTracker MST(MF); |
257 | // Print that MI with new machine metadata, which slot numbers should be |
258 | // assigned. |
259 | EXPECT_EQ("%1:gpr32 = LDRWui %0, 0 :: (load (s32) from %ir.p, " |
260 | "!alias.scope !0, !noalias !3)" , |
261 | print([&](raw_ostream &OS) { |
262 | MI.print(OS, MST, /*IsStandalone=*/false, /*SkipOpers=*/false, |
263 | /*SkipDebugLoc=*/false, /*AddNewLine=*/false); |
264 | })); |
265 | |
266 | std::vector<const MDNode *> Generated{Domain, Scope0, Scope1, Set0, Set1}; |
267 | // Examine machine metadata collected. They should match ones |
268 | // afore-generated. |
269 | std::vector<const MDNode *> Collected; |
270 | MachineModuleSlotTracker::MachineMDNodeListType MDList; |
271 | MST.collectMachineMDNodes(L&: MDList); |
272 | for (auto &MD : MDList) |
273 | Collected.push_back(x: MD.second); |
274 | |
275 | llvm::sort(C&: Generated); |
276 | llvm::sort(C&: Collected); |
277 | EXPECT_EQ(Collected, Generated); |
278 | |
279 | // FileCheck the output from MIR printer. |
280 | std::string Output = print(PrintFn: [&](raw_ostream &OS) { printMIR(OS, MF: *MF); }); |
281 | std::string CheckString = R"( |
282 | CHECK: machineMetadataNodes: |
283 | CHECK-DAG: ![[MMDOMAIN:[0-9]+]] = distinct !{!{{[0-9]+}}, !"domain"} |
284 | CHECK-DAG: ![[MMSCOPE0:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope0"} |
285 | CHECK-DAG: ![[MMSCOPE1:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope1"} |
286 | CHECK-DAG: ![[MMSET0:[0-9]+]] = !{![[MMSCOPE0]]} |
287 | CHECK-DAG: ![[MMSET1:[0-9]+]] = !{![[MMSCOPE1]]} |
288 | CHECK: body: |
289 | CHECK: %1:gpr32 = LDRWui %0, 0 :: (load (s32) from %ir.p, !alias.scope ![[MMSET0]], !noalias ![[MMSET1]]) |
290 | )" ; |
291 | EXPECT_TRUE(checkOutput(CheckString, Output)); |
292 | } |
293 | |
294 | TEST_F(MachineMetadataTest, isMetaInstruction) { |
295 | auto TM = createTargetMachine(TT: Triple::normalize(Str: "x86_64--" ), CPU: "" , FS: "" ); |
296 | if (!TM) |
297 | GTEST_SKIP(); |
298 | |
299 | StringRef MIRString = R"MIR( |
300 | --- | |
301 | define void @test0(i32 %b) { |
302 | ret void |
303 | } |
304 | !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) |
305 | !1 = !DIFile(filename: "a.c", directory: "/tmp") |
306 | !2 = !{i32 7, !"Dwarf Version", i32 4} |
307 | !3 = !{i32 2, !"Debug Info Version", i32 3} |
308 | !4 = !{i32 1, !"wchar_size", i32 4} |
309 | !5 = !{i32 7, !"uwtable", i32 1} |
310 | !6 = !{i32 7, !"frame-pointer", i32 2} |
311 | !7 = !{!""} |
312 | !8 = distinct !DISubprogram(name: "test0", scope: !1, file: !1, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !12) |
313 | !9 = !DISubroutineType(types: !10) |
314 | !10 = !{null, !11} |
315 | !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) |
316 | !12 = !{} |
317 | !13 = !DILocalVariable(name: "b", arg: 1, scope: !8, file: !1, line: 1, type: !11) |
318 | !14 = !DILocation(line: 1, column: 16, scope: !8) |
319 | ... |
320 | --- |
321 | name: test0 |
322 | machineFunctionInfo |
323 | body: | |
324 | bb.0: |
325 | $rdi = IMPLICIT_DEF |
326 | KILL $rsi |
327 | CFI_INSTRUCTION undefined $rax |
328 | EH_LABEL 0 |
329 | GC_LABEL 0 |
330 | DBG_VALUE $rax, $noreg, !13, !DIExpression(), debug-location !14 |
331 | DBG_LABEL 0 |
332 | LIFETIME_START 0 |
333 | LIFETIME_END 0 |
334 | PSEUDO_PROBE 6699318081062747564, 1, 0, 0 |
335 | $xmm0 = ARITH_FENCE $xmm0 |
336 | MEMBARRIER |
337 | ... |
338 | )MIR" ; |
339 | |
340 | MachineModuleInfo MMI(TM.get()); |
341 | M = parseMIR(TM: *TM, MIRCode: MIRString, FnName: "test0" , MMI); |
342 | ASSERT_TRUE(M); |
343 | |
344 | auto *MF = MMI.getMachineFunction(F: *M->getFunction(Name: "test0" )); |
345 | auto *MBB = MF->getBlockNumbered(N: 0); |
346 | |
347 | for (auto It = MBB->begin(); It != MBB->end(); ++It) { |
348 | MachineInstr &MI = *It; |
349 | ASSERT_TRUE(MI.isMetaInstruction()); |
350 | } |
351 | } |
352 | |
353 | TEST_F(MachineMetadataTest, MMSlotTrackerX64) { |
354 | auto TM = createTargetMachine(TT: Triple::normalize(Str: "x86_64--" ), CPU: "" , FS: "" ); |
355 | if (!TM) |
356 | GTEST_SKIP(); |
357 | |
358 | StringRef MIRString = R"MIR( |
359 | --- | |
360 | define i32 @test0(i32* %p) { |
361 | %r = load i32, i32* %p, align 4 |
362 | ret i32 %r |
363 | } |
364 | ... |
365 | --- |
366 | name: test0 |
367 | liveins: |
368 | - { reg: '$rdi', virtual-reg: '%0' } |
369 | body: | |
370 | bb.0 (%ir-block.0): |
371 | liveins: $rdi |
372 | |
373 | %0:gr64 = COPY $rdi |
374 | %1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load (s32) from %ir.p) |
375 | ... |
376 | )MIR" ; |
377 | |
378 | MachineModuleInfo MMI(TM.get()); |
379 | M = parseMIR(TM: *TM, MIRCode: MIRString, FnName: "test0" , MMI); |
380 | ASSERT_TRUE(M); |
381 | |
382 | auto *MF = MMI.getMachineFunction(F: *M->getFunction(Name: "test0" )); |
383 | auto *MBB = MF->getBlockNumbered(N: 0); |
384 | |
385 | auto &MI = MBB->back(); |
386 | ASSERT_FALSE(MI.memoperands_empty()); |
387 | ASSERT_TRUE(MI.hasOneMemOperand()); |
388 | |
389 | // Create and attached scoped AA metadata on that instruction with one MMO. |
390 | MDBuilder MDB(Context); |
391 | MDNode *Domain = MDB.createAnonymousAliasScopeDomain(Name: "domain" ); |
392 | MDNode *Scope0 = MDB.createAnonymousAliasScope(Domain, Name: "scope0" ); |
393 | MDNode *Scope1 = MDB.createAnonymousAliasScope(Domain, Name: "scope1" ); |
394 | MDNode *Set0 = MDNode::get(Context, MDs: {Scope0}); |
395 | MDNode *Set1 = MDNode::get(Context, MDs: {Scope1}); |
396 | |
397 | AAMDNodes AAInfo; |
398 | AAInfo.TBAA = AAInfo.TBAAStruct = nullptr; |
399 | AAInfo.Scope = Set0; |
400 | AAInfo.NoAlias = Set1; |
401 | |
402 | auto *OldMMO = MI.memoperands().front(); |
403 | auto *NewMMO = MF->getMachineMemOperand(MMO: OldMMO, AAInfo); |
404 | MI.setMemRefs(MF&: *MF, MemRefs: NewMMO); |
405 | |
406 | MachineModuleSlotTracker MST(MF); |
407 | // Print that MI with new machine metadata, which slot numbers should be |
408 | // assigned. |
409 | EXPECT_EQ("%1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load (s32) from %ir.p, " |
410 | "!alias.scope !0, !noalias !3)" , |
411 | print([&](raw_ostream &OS) { |
412 | MI.print(OS, MST, /*IsStandalone=*/false, /*SkipOpers=*/false, |
413 | /*SkipDebugLoc=*/false, /*AddNewLine=*/false); |
414 | })); |
415 | |
416 | std::vector<const MDNode *> Generated{Domain, Scope0, Scope1, Set0, Set1}; |
417 | // Examine machine metadata collected. They should match ones |
418 | // afore-generated. |
419 | std::vector<const MDNode *> Collected; |
420 | MachineModuleSlotTracker::MachineMDNodeListType MDList; |
421 | MST.collectMachineMDNodes(L&: MDList); |
422 | for (auto &MD : MDList) |
423 | Collected.push_back(x: MD.second); |
424 | |
425 | llvm::sort(C&: Generated); |
426 | llvm::sort(C&: Collected); |
427 | EXPECT_EQ(Collected, Generated); |
428 | |
429 | // FileCheck the output from MIR printer. |
430 | std::string Output = print(PrintFn: [&](raw_ostream &OS) { printMIR(OS, MF: *MF); }); |
431 | std::string CheckString = R"( |
432 | CHECK: machineMetadataNodes: |
433 | CHECK-DAG: ![[MMDOMAIN:[0-9]+]] = distinct !{!{{[0-9]+}}, !"domain"} |
434 | CHECK-DAG: ![[MMSCOPE0:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope0"} |
435 | CHECK-DAG: ![[MMSCOPE1:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope1"} |
436 | CHECK-DAG: ![[MMSET0:[0-9]+]] = !{![[MMSCOPE0]]} |
437 | CHECK-DAG: ![[MMSET1:[0-9]+]] = !{![[MMSCOPE1]]} |
438 | CHECK: body: |
439 | CHECK: %1:gr32 = MOV32rm %0, 1, $noreg, 0, $noreg :: (load (s32) from %ir.p, !alias.scope ![[MMSET0]], !noalias ![[MMSET1]]) |
440 | )" ; |
441 | EXPECT_TRUE(checkOutput(CheckString, Output)); |
442 | } |
443 | |
444 | TEST_F(MachineMetadataTest, MMSlotTrackerAMDGPU) { |
445 | auto TM = createTargetMachine(TT: Triple::normalize(Str: "amdgcn-amd-amdhsa" ), |
446 | CPU: "gfx1010" , FS: "" ); |
447 | if (!TM) |
448 | GTEST_SKIP(); |
449 | |
450 | StringRef MIRString = R"MIR( |
451 | --- | |
452 | define i32 @test0(i32* %p) { |
453 | %r = load i32, i32* %p, align 4 |
454 | ret i32 %r |
455 | } |
456 | ... |
457 | --- |
458 | name: test0 |
459 | liveins: |
460 | - { reg: '$vgpr0', virtual-reg: '%0' } |
461 | - { reg: '$vgpr1', virtual-reg: '%1' } |
462 | - { reg: '$sgpr30_sgpr31', virtual-reg: '%2' } |
463 | body: | |
464 | bb.0 (%ir-block.0): |
465 | liveins: $vgpr0, $vgpr1, $sgpr30_sgpr31 |
466 | |
467 | %2:sreg_64 = COPY $sgpr30_sgpr31 |
468 | %1:vgpr_32 = COPY $vgpr1 |
469 | %0:vgpr_32 = COPY $vgpr0 |
470 | %8:vreg_64 = REG_SEQUENCE %0, %subreg.sub0, %1, %subreg.sub1 |
471 | %6:vreg_64 = COPY %8 |
472 | %5:vgpr_32 = FLAT_LOAD_DWORD killed %6, 0, 0, implicit $exec, implicit $flat_scr :: (load (s32) from %ir.p) |
473 | ... |
474 | )MIR" ; |
475 | |
476 | MachineModuleInfo MMI(TM.get()); |
477 | M = parseMIR(TM: *TM, MIRCode: MIRString, FnName: "test0" , MMI); |
478 | ASSERT_TRUE(M); |
479 | |
480 | auto *MF = MMI.getMachineFunction(F: *M->getFunction(Name: "test0" )); |
481 | auto *MBB = MF->getBlockNumbered(N: 0); |
482 | |
483 | auto &MI = MBB->back(); |
484 | ASSERT_FALSE(MI.memoperands_empty()); |
485 | ASSERT_TRUE(MI.hasOneMemOperand()); |
486 | |
487 | // Create and attached scoped AA metadata on that instruction with one MMO. |
488 | MDBuilder MDB(Context); |
489 | MDNode *Domain = MDB.createAnonymousAliasScopeDomain(Name: "domain" ); |
490 | MDNode *Scope0 = MDB.createAnonymousAliasScope(Domain, Name: "scope0" ); |
491 | MDNode *Scope1 = MDB.createAnonymousAliasScope(Domain, Name: "scope1" ); |
492 | MDNode *Set0 = MDNode::get(Context, MDs: {Scope0}); |
493 | MDNode *Set1 = MDNode::get(Context, MDs: {Scope1}); |
494 | |
495 | AAMDNodes AAInfo; |
496 | AAInfo.TBAA = AAInfo.TBAAStruct = nullptr; |
497 | AAInfo.Scope = Set0; |
498 | AAInfo.NoAlias = Set1; |
499 | |
500 | auto *OldMMO = MI.memoperands().front(); |
501 | auto *NewMMO = MF->getMachineMemOperand(MMO: OldMMO, AAInfo); |
502 | MI.setMemRefs(MF&: *MF, MemRefs: NewMMO); |
503 | |
504 | MachineModuleSlotTracker MST(MF); |
505 | // Print that MI with new machine metadata, which slot numbers should be |
506 | // assigned. |
507 | EXPECT_EQ( |
508 | "%5:vgpr_32 = FLAT_LOAD_DWORD killed %4, 0, 0, implicit $exec, implicit " |
509 | "$flat_scr :: (load (s32) from %ir.p, !alias.scope !0, !noalias !3)" , |
510 | print([&](raw_ostream &OS) { |
511 | MI.print(OS, MST, /*IsStandalone=*/false, /*SkipOpers=*/false, |
512 | /*SkipDebugLoc=*/false, /*AddNewLine=*/false); |
513 | })); |
514 | |
515 | std::vector<const MDNode *> Generated{Domain, Scope0, Scope1, Set0, Set1}; |
516 | // Examine machine metadata collected. They should match ones |
517 | // afore-generated. |
518 | std::vector<const MDNode *> Collected; |
519 | MachineModuleSlotTracker::MachineMDNodeListType MDList; |
520 | MST.collectMachineMDNodes(L&: MDList); |
521 | for (auto &MD : MDList) |
522 | Collected.push_back(x: MD.second); |
523 | |
524 | llvm::sort(C&: Generated); |
525 | llvm::sort(C&: Collected); |
526 | EXPECT_EQ(Collected, Generated); |
527 | |
528 | // FileCheck the output from MIR printer. |
529 | std::string Output = print(PrintFn: [&](raw_ostream &OS) { printMIR(OS, MF: *MF); }); |
530 | std::string CheckString = R"( |
531 | CHECK: machineMetadataNodes: |
532 | CHECK-DAG: ![[MMDOMAIN:[0-9]+]] = distinct !{!{{[0-9]+}}, !"domain"} |
533 | CHECK-DAG: ![[MMSCOPE0:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope0"} |
534 | CHECK-DAG: ![[MMSCOPE1:[0-9]+]] = distinct !{!{{[0-9]+}}, ![[MMDOMAIN]], !"scope1"} |
535 | CHECK-DAG: ![[MMSET0:[0-9]+]] = !{![[MMSCOPE0]]} |
536 | CHECK-DAG: ![[MMSET1:[0-9]+]] = !{![[MMSCOPE1]]} |
537 | CHECK: body: |
538 | 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]]) |
539 | )" ; |
540 | EXPECT_TRUE(checkOutput(CheckString, Output)); |
541 | } |
542 | |
543 | TEST_F(MachineMetadataTest, TiedOpsRewritten) { |
544 | auto TM = createTargetMachine(TT: Triple::normalize(Str: "powerpc64--" ), CPU: "" , FS: "" ); |
545 | if (!TM) |
546 | GTEST_SKIP(); |
547 | StringRef MIRString = R"MIR( |
548 | --- |
549 | name: foo |
550 | alignment: 16 |
551 | tracksRegLiveness: true |
552 | frameInfo: |
553 | maxAlignment: 16 |
554 | machineFunctionInfo: {} |
555 | body: | |
556 | bb.0: |
557 | liveins: $r3 |
558 | %0:gprc = COPY $r3 |
559 | %0 = RLWIMI killed %0, $r3, 1, 0, 30 |
560 | $r3 = COPY %0 |
561 | BLR8 implicit $r3, implicit $lr8, implicit $rm |
562 | |
563 | ... |
564 | )MIR" ; |
565 | MachineModuleInfo MMI(TM.get()); |
566 | M = parseMIR(TM: *TM, MIRCode: MIRString, FnName: "foo" , MMI); |
567 | ASSERT_TRUE(M); |
568 | auto *MF = MMI.getMachineFunction(F: *M->getFunction(Name: "foo" )); |
569 | MachineFunctionProperties &Properties = MF->getProperties(); |
570 | ASSERT_TRUE(Properties.hasProperty( |
571 | MachineFunctionProperties::Property::TiedOpsRewritten)); |
572 | } |
573 | |
574 | TEST_F(MachineMetadataTest, NoTiedOpsRewritten) { |
575 | auto TM = createTargetMachine(TT: Triple::normalize(Str: "powerpc64--" ), CPU: "" , FS: "" ); |
576 | if (!TM) |
577 | GTEST_SKIP(); |
578 | StringRef MIRString = R"MIR( |
579 | --- |
580 | name: foo |
581 | alignment: 16 |
582 | tracksRegLiveness: true |
583 | frameInfo: |
584 | maxAlignment: 16 |
585 | machineFunctionInfo: {} |
586 | body: | |
587 | bb.0: |
588 | liveins: $r3 |
589 | %0:gprc = COPY $r3 |
590 | %1:gprc = RLWIMI killed %0, $r3, 1, 0, 30 |
591 | $r3 = COPY %1 |
592 | BLR8 implicit $r3, implicit $lr8, implicit $rm |
593 | |
594 | ... |
595 | )MIR" ; |
596 | MachineModuleInfo MMI(TM.get()); |
597 | M = parseMIR(TM: *TM, MIRCode: MIRString, FnName: "foo" , MMI); |
598 | ASSERT_TRUE(M); |
599 | auto *MF = MMI.getMachineFunction(F: *M->getFunction(Name: "foo" )); |
600 | MachineFunctionProperties &Properties = MF->getProperties(); |
601 | ASSERT_FALSE(Properties.hasProperty( |
602 | MachineFunctionProperties::Property::TiedOpsRewritten)); |
603 | } |
604 | |