xref: /llvm-project/llvm/unittests/CodeGen/MachineInstrTest.cpp (revision 1d6ebdfb66b9d63d34f34ec6ac7ec57eff7cd24b)
1 //===- MachineInstrTest.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/CodeGen/MachineBasicBlock.h"
10 #include "llvm/CodeGen/MachineInstr.h"
11 #include "llvm/CodeGen/MachineFunction.h"
12 #include "llvm/CodeGen/MachineMemOperand.h"
13 #include "llvm/CodeGen/MachineModuleInfo.h"
14 #include "llvm/CodeGen/TargetFrameLowering.h"
15 #include "llvm/CodeGen/TargetInstrInfo.h"
16 #include "llvm/CodeGen/TargetLowering.h"
17 #include "llvm/CodeGen/TargetSubtargetInfo.h"
18 #include "llvm/IR/DebugInfoMetadata.h"
19 #include "llvm/IR/IRBuilder.h"
20 #include "llvm/IR/ModuleSlotTracker.h"
21 #include "llvm/MC/MCAsmInfo.h"
22 #include "llvm/MC/MCSymbol.h"
23 #include "llvm/Support/TargetRegistry.h"
24 #include "llvm/Support/TargetSelect.h"
25 #include "llvm/Target/TargetMachine.h"
26 #include "llvm/Target/TargetOptions.h"
27 #include "gtest/gtest.h"
28 
29 using namespace llvm;
30 
31 namespace {
32 // Include helper functions to ease the manipulation of MachineFunctions.
33 #include "MFCommon.inc"
34 
35 std::unique_ptr<MCContext> createMCContext(MCAsmInfo *AsmInfo) {
36   return std::make_unique<MCContext>(
37       AsmInfo, nullptr, nullptr, nullptr, nullptr, false);
38 }
39 
40 // This test makes sure that MachineInstr::isIdenticalTo handles Defs correctly
41 // for various combinations of IgnoreDefs, and also that it is symmetrical.
42 TEST(IsIdenticalToTest, DifferentDefs) {
43   LLVMContext Ctx;
44   Module Mod("Module", Ctx);
45   auto MF = createMachineFunction(Ctx, Mod);
46 
47   unsigned short NumOps = 2;
48   unsigned char NumDefs = 1;
49   MCOperandInfo OpInfo[] = {
50       {0, 0, MCOI::OPERAND_REGISTER, 0},
51       {0, 1 << MCOI::OptionalDef, MCOI::OPERAND_REGISTER, 0}};
52   MCInstrDesc MCID = {
53       0, NumOps,  NumDefs, 0,     0, 1ULL << MCID::HasOptionalDef,
54       0, nullptr, nullptr, OpInfo};
55 
56   // Create two MIs with different virtual reg defs and the same uses.
57   unsigned VirtualDef1 = -42; // The value doesn't matter, but the sign does.
58   unsigned VirtualDef2 = -43;
59   unsigned VirtualUse = -44;
60 
61   auto MI1 = MF->CreateMachineInstr(MCID, DebugLoc());
62   MI1->addOperand(*MF, MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true));
63   MI1->addOperand(*MF, MachineOperand::CreateReg(VirtualUse, /*isDef*/ false));
64 
65   auto MI2 = MF->CreateMachineInstr(MCID, DebugLoc());
66   MI2->addOperand(*MF, MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true));
67   MI2->addOperand(*MF, MachineOperand::CreateReg(VirtualUse, /*isDef*/ false));
68 
69   // Check that they are identical when we ignore virtual register defs, but not
70   // when we check defs.
71   ASSERT_FALSE(MI1->isIdenticalTo(*MI2, MachineInstr::CheckDefs));
72   ASSERT_FALSE(MI2->isIdenticalTo(*MI1, MachineInstr::CheckDefs));
73 
74   ASSERT_TRUE(MI1->isIdenticalTo(*MI2, MachineInstr::IgnoreVRegDefs));
75   ASSERT_TRUE(MI2->isIdenticalTo(*MI1, MachineInstr::IgnoreVRegDefs));
76 
77   // Create two MIs with different virtual reg defs, and a def or use of a
78   // sentinel register.
79   unsigned SentinelReg = 0;
80 
81   auto MI3 = MF->CreateMachineInstr(MCID, DebugLoc());
82   MI3->addOperand(*MF, MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true));
83   MI3->addOperand(*MF, MachineOperand::CreateReg(SentinelReg, /*isDef*/ true));
84 
85   auto MI4 = MF->CreateMachineInstr(MCID, DebugLoc());
86   MI4->addOperand(*MF, MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true));
87   MI4->addOperand(*MF, MachineOperand::CreateReg(SentinelReg, /*isDef*/ false));
88 
89   // Check that they are never identical.
90   ASSERT_FALSE(MI3->isIdenticalTo(*MI4, MachineInstr::CheckDefs));
91   ASSERT_FALSE(MI4->isIdenticalTo(*MI3, MachineInstr::CheckDefs));
92 
93   ASSERT_FALSE(MI3->isIdenticalTo(*MI4, MachineInstr::IgnoreVRegDefs));
94   ASSERT_FALSE(MI4->isIdenticalTo(*MI3, MachineInstr::IgnoreVRegDefs));
95 }
96 
97 // Check that MachineInstrExpressionTrait::isEqual is symmetric and in sync with
98 // MachineInstrExpressionTrait::getHashValue
99 void checkHashAndIsEqualMatch(MachineInstr *MI1, MachineInstr *MI2) {
100   bool IsEqual1 = MachineInstrExpressionTrait::isEqual(MI1, MI2);
101   bool IsEqual2 = MachineInstrExpressionTrait::isEqual(MI2, MI1);
102 
103   ASSERT_EQ(IsEqual1, IsEqual2);
104 
105   auto Hash1 = MachineInstrExpressionTrait::getHashValue(MI1);
106   auto Hash2 = MachineInstrExpressionTrait::getHashValue(MI2);
107 
108   ASSERT_EQ(IsEqual1, Hash1 == Hash2);
109 }
110 
111 // This test makes sure that MachineInstrExpressionTraits::isEqual is in sync
112 // with MachineInstrExpressionTraits::getHashValue.
113 TEST(MachineInstrExpressionTraitTest, IsEqualAgreesWithGetHashValue) {
114   LLVMContext Ctx;
115   Module Mod("Module", Ctx);
116   auto MF = createMachineFunction(Ctx, Mod);
117 
118   unsigned short NumOps = 2;
119   unsigned char NumDefs = 1;
120   MCOperandInfo OpInfo[] = {
121       {0, 0, MCOI::OPERAND_REGISTER, 0},
122       {0, 1 << MCOI::OptionalDef, MCOI::OPERAND_REGISTER, 0}};
123   MCInstrDesc MCID = {
124       0, NumOps,  NumDefs, 0,     0, 1ULL << MCID::HasOptionalDef,
125       0, nullptr, nullptr, OpInfo};
126 
127   // Define a series of instructions with different kinds of operands and make
128   // sure that the hash function is consistent with isEqual for various
129   // combinations of them.
130   unsigned VirtualDef1 = -42;
131   unsigned VirtualDef2 = -43;
132   unsigned VirtualReg = -44;
133   unsigned SentinelReg = 0;
134   unsigned PhysicalReg = 45;
135 
136   auto VD1VU = MF->CreateMachineInstr(MCID, DebugLoc());
137   VD1VU->addOperand(*MF,
138                     MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true));
139   VD1VU->addOperand(*MF,
140                     MachineOperand::CreateReg(VirtualReg, /*isDef*/ false));
141 
142   auto VD2VU = MF->CreateMachineInstr(MCID, DebugLoc());
143   VD2VU->addOperand(*MF,
144                     MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true));
145   VD2VU->addOperand(*MF,
146                     MachineOperand::CreateReg(VirtualReg, /*isDef*/ false));
147 
148   auto VD1SU = MF->CreateMachineInstr(MCID, DebugLoc());
149   VD1SU->addOperand(*MF,
150                     MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true));
151   VD1SU->addOperand(*MF,
152                     MachineOperand::CreateReg(SentinelReg, /*isDef*/ false));
153 
154   auto VD1SD = MF->CreateMachineInstr(MCID, DebugLoc());
155   VD1SD->addOperand(*MF,
156                     MachineOperand::CreateReg(VirtualDef1, /*isDef*/ true));
157   VD1SD->addOperand(*MF,
158                     MachineOperand::CreateReg(SentinelReg, /*isDef*/ true));
159 
160   auto VD2PU = MF->CreateMachineInstr(MCID, DebugLoc());
161   VD2PU->addOperand(*MF,
162                     MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true));
163   VD2PU->addOperand(*MF,
164                     MachineOperand::CreateReg(PhysicalReg, /*isDef*/ false));
165 
166   auto VD2PD = MF->CreateMachineInstr(MCID, DebugLoc());
167   VD2PD->addOperand(*MF,
168                     MachineOperand::CreateReg(VirtualDef2, /*isDef*/ true));
169   VD2PD->addOperand(*MF,
170                     MachineOperand::CreateReg(PhysicalReg, /*isDef*/ true));
171 
172   checkHashAndIsEqualMatch(VD1VU, VD2VU);
173   checkHashAndIsEqualMatch(VD1VU, VD1SU);
174   checkHashAndIsEqualMatch(VD1VU, VD1SD);
175   checkHashAndIsEqualMatch(VD1VU, VD2PU);
176   checkHashAndIsEqualMatch(VD1VU, VD2PD);
177 
178   checkHashAndIsEqualMatch(VD2VU, VD1SU);
179   checkHashAndIsEqualMatch(VD2VU, VD1SD);
180   checkHashAndIsEqualMatch(VD2VU, VD2PU);
181   checkHashAndIsEqualMatch(VD2VU, VD2PD);
182 
183   checkHashAndIsEqualMatch(VD1SU, VD1SD);
184   checkHashAndIsEqualMatch(VD1SU, VD2PU);
185   checkHashAndIsEqualMatch(VD1SU, VD2PD);
186 
187   checkHashAndIsEqualMatch(VD1SD, VD2PU);
188   checkHashAndIsEqualMatch(VD1SD, VD2PD);
189 
190   checkHashAndIsEqualMatch(VD2PU, VD2PD);
191 }
192 
193 TEST(MachineInstrPrintingTest, DebugLocPrinting) {
194   LLVMContext Ctx;
195   Module Mod("Module", Ctx);
196   auto MF = createMachineFunction(Ctx, Mod);
197 
198   MCOperandInfo OpInfo{0, 0, MCOI::OPERAND_REGISTER, 0};
199   MCInstrDesc MCID = {0, 1, 1, 0, 0, 0, 0, nullptr, nullptr, &OpInfo};
200 
201   DIFile *DIF = DIFile::getDistinct(Ctx, "filename", "");
202   DISubprogram *DIS = DISubprogram::getDistinct(
203       Ctx, nullptr, "", "", DIF, 0, nullptr, 0, nullptr, 0, 0, DINode::FlagZero,
204       DISubprogram::SPFlagZero, nullptr);
205   DILocation *DIL = DILocation::get(Ctx, 1, 5, DIS);
206   DebugLoc DL(DIL);
207   MachineInstr *MI = MF->CreateMachineInstr(MCID, DL);
208   MI->addOperand(*MF, MachineOperand::CreateReg(0, /*isDef*/ true));
209 
210   std::string str;
211   raw_string_ostream OS(str);
212   MI->print(OS, /*IsStandalone*/true, /*SkipOpers*/false, /*SkipDebugLoc*/false,
213             /*AddNewLine*/false);
214   ASSERT_TRUE(
215       StringRef(OS.str()).startswith("$noreg = UNKNOWN debug-location "));
216   ASSERT_TRUE(
217       StringRef(OS.str()).endswith("filename:1:5"));
218 }
219 
220 TEST(MachineInstrSpan, DistanceBegin) {
221   LLVMContext Ctx;
222   Module Mod("Module", Ctx);
223   auto MF = createMachineFunction(Ctx, Mod);
224   auto MBB = MF->CreateMachineBasicBlock();
225 
226   MCInstrDesc MCID = {0, 0, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr};
227 
228   auto MII = MBB->begin();
229   MachineInstrSpan MIS(MII, MBB);
230   ASSERT_TRUE(MIS.empty());
231 
232   auto MI = MF->CreateMachineInstr(MCID, DebugLoc());
233   MBB->insert(MII, MI);
234   ASSERT_TRUE(std::distance(MIS.begin(), MII) == 1);
235 }
236 
237 TEST(MachineInstrSpan, DistanceEnd) {
238   LLVMContext Ctx;
239   Module Mod("Module", Ctx);
240   auto MF = createMachineFunction(Ctx, Mod);
241   auto MBB = MF->CreateMachineBasicBlock();
242 
243   MCInstrDesc MCID = {0, 0, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr};
244 
245   auto MII = MBB->end();
246   MachineInstrSpan MIS(MII, MBB);
247   ASSERT_TRUE(MIS.empty());
248 
249   auto MI = MF->CreateMachineInstr(MCID, DebugLoc());
250   MBB->insert(MII, MI);
251   ASSERT_TRUE(std::distance(MIS.begin(), MII) == 1);
252 }
253 
254 TEST(MachineInstrExtraInfo, AddExtraInfo) {
255   LLVMContext Ctx;
256   Module Mod("Module", Ctx);
257   auto MF = createMachineFunction(Ctx, Mod);
258   MCInstrDesc MCID = {0, 0, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr};
259 
260   auto MI = MF->CreateMachineInstr(MCID, DebugLoc());
261   auto MAI = MCAsmInfo();
262   auto MC = createMCContext(&MAI);
263   auto MMO = MF->getMachineMemOperand(MachinePointerInfo(),
264                                       MachineMemOperand::MOLoad, 8, Align(8));
265   SmallVector<MachineMemOperand *, 2> MMOs;
266   MMOs.push_back(MMO);
267   MCSymbol *Sym1 = MC->createTempSymbol("pre_label", false);
268   MCSymbol *Sym2 = MC->createTempSymbol("post_label", false);
269   MDNode *MDN = MDNode::getDistinct(Ctx, None);
270 
271   ASSERT_TRUE(MI->memoperands_empty());
272   ASSERT_FALSE(MI->getPreInstrSymbol());
273   ASSERT_FALSE(MI->getPostInstrSymbol());
274   ASSERT_FALSE(MI->getHeapAllocMarker());
275 
276   MI->setMemRefs(*MF, MMOs);
277   ASSERT_TRUE(MI->memoperands().size() == 1);
278   ASSERT_FALSE(MI->getPreInstrSymbol());
279   ASSERT_FALSE(MI->getPostInstrSymbol());
280   ASSERT_FALSE(MI->getHeapAllocMarker());
281 
282   MI->setPreInstrSymbol(*MF, Sym1);
283   ASSERT_TRUE(MI->memoperands().size() == 1);
284   ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
285   ASSERT_FALSE(MI->getPostInstrSymbol());
286   ASSERT_FALSE(MI->getHeapAllocMarker());
287 
288   MI->setPostInstrSymbol(*MF, Sym2);
289   ASSERT_TRUE(MI->memoperands().size() == 1);
290   ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
291   ASSERT_TRUE(MI->getPostInstrSymbol() == Sym2);
292   ASSERT_FALSE(MI->getHeapAllocMarker());
293 
294   MI->setHeapAllocMarker(*MF, MDN);
295   ASSERT_TRUE(MI->memoperands().size() == 1);
296   ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
297   ASSERT_TRUE(MI->getPostInstrSymbol() == Sym2);
298   ASSERT_TRUE(MI->getHeapAllocMarker() == MDN);
299 }
300 
301 TEST(MachineInstrExtraInfo, ChangeExtraInfo) {
302   LLVMContext Ctx;
303   Module Mod("Module", Ctx);
304   auto MF = createMachineFunction(Ctx, Mod);
305   MCInstrDesc MCID = {0, 0, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr};
306 
307   auto MI = MF->CreateMachineInstr(MCID, DebugLoc());
308   auto MAI = MCAsmInfo();
309   auto MC = createMCContext(&MAI);
310   auto MMO = MF->getMachineMemOperand(MachinePointerInfo(),
311                                       MachineMemOperand::MOLoad, 8, Align(8));
312   SmallVector<MachineMemOperand *, 2> MMOs;
313   MMOs.push_back(MMO);
314   MCSymbol *Sym1 = MC->createTempSymbol("pre_label", false);
315   MCSymbol *Sym2 = MC->createTempSymbol("post_label", false);
316   MDNode *MDN = MDNode::getDistinct(Ctx, None);
317 
318   MI->setMemRefs(*MF, MMOs);
319   MI->setPreInstrSymbol(*MF, Sym1);
320   MI->setPostInstrSymbol(*MF, Sym2);
321   MI->setHeapAllocMarker(*MF, MDN);
322 
323   MMOs.push_back(MMO);
324 
325   MI->setMemRefs(*MF, MMOs);
326   ASSERT_TRUE(MI->memoperands().size() == 2);
327   ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
328   ASSERT_TRUE(MI->getPostInstrSymbol() == Sym2);
329   ASSERT_TRUE(MI->getHeapAllocMarker() == MDN);
330 
331   MI->setPostInstrSymbol(*MF, Sym1);
332   ASSERT_TRUE(MI->memoperands().size() == 2);
333   ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
334   ASSERT_TRUE(MI->getPostInstrSymbol() == Sym1);
335   ASSERT_TRUE(MI->getHeapAllocMarker() == MDN);
336 }
337 
338 TEST(MachineInstrExtraInfo, RemoveExtraInfo) {
339   LLVMContext Ctx;
340   Module Mod("Module", Ctx);
341   auto MF = createMachineFunction(Ctx, Mod);
342   MCInstrDesc MCID = {0, 0, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr};
343 
344   auto MI = MF->CreateMachineInstr(MCID, DebugLoc());
345   auto MAI = MCAsmInfo();
346   auto MC = createMCContext(&MAI);
347   auto MMO = MF->getMachineMemOperand(MachinePointerInfo(),
348                                       MachineMemOperand::MOLoad, 8, Align(8));
349   SmallVector<MachineMemOperand *, 2> MMOs;
350   MMOs.push_back(MMO);
351   MMOs.push_back(MMO);
352   MCSymbol *Sym1 = MC->createTempSymbol("pre_label", false);
353   MCSymbol *Sym2 = MC->createTempSymbol("post_label", false);
354   MDNode *MDN = MDNode::getDistinct(Ctx, None);
355 
356   MI->setMemRefs(*MF, MMOs);
357   MI->setPreInstrSymbol(*MF, Sym1);
358   MI->setPostInstrSymbol(*MF, Sym2);
359   MI->setHeapAllocMarker(*MF, MDN);
360 
361   MI->setPostInstrSymbol(*MF, nullptr);
362   ASSERT_TRUE(MI->memoperands().size() == 2);
363   ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
364   ASSERT_FALSE(MI->getPostInstrSymbol());
365   ASSERT_TRUE(MI->getHeapAllocMarker() == MDN);
366 
367   MI->setHeapAllocMarker(*MF, nullptr);
368   ASSERT_TRUE(MI->memoperands().size() == 2);
369   ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
370   ASSERT_FALSE(MI->getPostInstrSymbol());
371   ASSERT_FALSE(MI->getHeapAllocMarker());
372 
373   MI->setPreInstrSymbol(*MF, nullptr);
374   ASSERT_TRUE(MI->memoperands().size() == 2);
375   ASSERT_FALSE(MI->getPreInstrSymbol());
376   ASSERT_FALSE(MI->getPostInstrSymbol());
377   ASSERT_FALSE(MI->getHeapAllocMarker());
378 
379   MI->setMemRefs(*MF, {});
380   ASSERT_TRUE(MI->memoperands_empty());
381   ASSERT_FALSE(MI->getPreInstrSymbol());
382   ASSERT_FALSE(MI->getPostInstrSymbol());
383   ASSERT_FALSE(MI->getHeapAllocMarker());
384 }
385 
386 static_assert(std::is_trivially_copyable<MCOperand>::value,
387               "trivially copyable");
388 
389 } // end namespace
390