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/MachineInstr.h"
10#include "llvm/CodeGen/MachineBasicBlock.h"
11#include "llvm/CodeGen/MachineFunction.h"
12#include "llvm/CodeGen/MachineInstrBuilder.h"
13#include "llvm/CodeGen/MachineMemOperand.h"
14#include "llvm/CodeGen/MachineModuleInfo.h"
15#include "llvm/CodeGen/TargetFrameLowering.h"
16#include "llvm/CodeGen/TargetInstrInfo.h"
17#include "llvm/CodeGen/TargetLowering.h"
18#include "llvm/CodeGen/TargetSubtargetInfo.h"
19#include "llvm/IR/DebugInfoMetadata.h"
20#include "llvm/IR/IRBuilder.h"
21#include "llvm/IR/MemoryModelRelaxationAnnotations.h"
22#include "llvm/IR/ModuleSlotTracker.h"
23#include "llvm/MC/MCAsmInfo.h"
24#include "llvm/MC/MCSymbol.h"
25#include "llvm/MC/TargetRegistry.h"
26#include "llvm/Support/TargetSelect.h"
27#include "llvm/Target/TargetMachine.h"
28#include "llvm/Target/TargetOptions.h"
29#include "llvm/TargetParser/Triple.h"
30#include "gmock/gmock.h"
31#include "gtest/gtest.h"
32
33using namespace llvm;
34
35namespace {
36// Include helper functions to ease the manipulation of MachineFunctions.
37#include "MFCommon.inc"
38
39std::unique_ptr<MCContext> createMCContext(MCAsmInfo *AsmInfo) {
40 Triple TheTriple(/*ArchStr=*/"", /*VendorStr=*/"", /*OSStr=*/"",
41 /*EnvironmentStr=*/"elf");
42 return std::make_unique<MCContext>(args&: TheTriple, args&: AsmInfo, args: nullptr, args: nullptr,
43 args: nullptr, args: nullptr, args: false);
44}
45
46// This test makes sure that MachineInstr::isIdenticalTo handles Defs correctly
47// for various combinations of IgnoreDefs, and also that it is symmetrical.
48TEST(IsIdenticalToTest, DifferentDefs) {
49 LLVMContext Ctx;
50 Module Mod("Module", Ctx);
51 auto MF = createMachineFunction(Ctx, M&: Mod);
52
53 unsigned short NumOps = 2;
54 unsigned char NumDefs = 1;
55 struct {
56 MCInstrDesc MCID;
57 MCOperandInfo OpInfo[2];
58 } Table = {
59 .MCID: {.Opcode: 0, .NumOperands: NumOps, .NumDefs: NumDefs, .Size: 0, .SchedClass: 0, .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: 1ULL << MCID::HasOptionalDef, .TSFlags: 0},
60 .OpInfo: {{.RegClass: 0, .Flags: 0, .OperandType: MCOI::OPERAND_REGISTER, .Constraints: 0},
61 {.RegClass: 0, .Flags: 1 << MCOI::OptionalDef, .OperandType: MCOI::OPERAND_REGISTER, .Constraints: 0}}};
62
63 // Create two MIs with different virtual reg defs and the same uses.
64 unsigned VirtualDef1 = -42; // The value doesn't matter, but the sign does.
65 unsigned VirtualDef2 = -43;
66 unsigned VirtualUse = -44;
67
68 auto MI1 = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
69 MI1->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: VirtualDef1, /*isDef*/ true));
70 MI1->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: VirtualUse, /*isDef*/ false));
71
72 auto MI2 = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
73 MI2->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: VirtualDef2, /*isDef*/ true));
74 MI2->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: VirtualUse, /*isDef*/ false));
75
76 // Check that they are identical when we ignore virtual register defs, but not
77 // when we check defs.
78 ASSERT_FALSE(MI1->isIdenticalTo(*MI2, MachineInstr::CheckDefs));
79 ASSERT_FALSE(MI2->isIdenticalTo(*MI1, MachineInstr::CheckDefs));
80
81 ASSERT_TRUE(MI1->isIdenticalTo(*MI2, MachineInstr::IgnoreVRegDefs));
82 ASSERT_TRUE(MI2->isIdenticalTo(*MI1, MachineInstr::IgnoreVRegDefs));
83
84 // Create two MIs with different virtual reg defs, and a def or use of a
85 // sentinel register.
86 unsigned SentinelReg = 0;
87
88 auto MI3 = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
89 MI3->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: VirtualDef1, /*isDef*/ true));
90 MI3->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: SentinelReg, /*isDef*/ true));
91
92 auto MI4 = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
93 MI4->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: VirtualDef2, /*isDef*/ true));
94 MI4->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: SentinelReg, /*isDef*/ false));
95
96 // Check that they are never identical.
97 ASSERT_FALSE(MI3->isIdenticalTo(*MI4, MachineInstr::CheckDefs));
98 ASSERT_FALSE(MI4->isIdenticalTo(*MI3, MachineInstr::CheckDefs));
99
100 ASSERT_FALSE(MI3->isIdenticalTo(*MI4, MachineInstr::IgnoreVRegDefs));
101 ASSERT_FALSE(MI4->isIdenticalTo(*MI3, MachineInstr::IgnoreVRegDefs));
102}
103
104// Check that MachineInstrExpressionTrait::isEqual is symmetric and in sync with
105// MachineInstrExpressionTrait::getHashValue
106void checkHashAndIsEqualMatch(MachineInstr *MI1, MachineInstr *MI2) {
107 bool IsEqual1 = MachineInstrExpressionTrait::isEqual(LHS: MI1, RHS: MI2);
108 bool IsEqual2 = MachineInstrExpressionTrait::isEqual(LHS: MI2, RHS: MI1);
109
110 ASSERT_EQ(IsEqual1, IsEqual2);
111
112 auto Hash1 = MachineInstrExpressionTrait::getHashValue(MI: MI1);
113 auto Hash2 = MachineInstrExpressionTrait::getHashValue(MI: MI2);
114
115 ASSERT_EQ(IsEqual1, Hash1 == Hash2);
116}
117
118// This test makes sure that MachineInstrExpressionTraits::isEqual is in sync
119// with MachineInstrExpressionTraits::getHashValue.
120TEST(MachineInstrExpressionTraitTest, IsEqualAgreesWithGetHashValue) {
121 LLVMContext Ctx;
122 Module Mod("Module", Ctx);
123 auto MF = createMachineFunction(Ctx, M&: Mod);
124
125 unsigned short NumOps = 2;
126 unsigned char NumDefs = 1;
127 struct {
128 MCInstrDesc MCID;
129 MCOperandInfo OpInfo[2];
130 } Table = {
131 .MCID: {.Opcode: 0, .NumOperands: NumOps, .NumDefs: NumDefs, .Size: 0, .SchedClass: 0, .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: 1ULL << MCID::HasOptionalDef, .TSFlags: 0},
132 .OpInfo: {{.RegClass: 0, .Flags: 0, .OperandType: MCOI::OPERAND_REGISTER, .Constraints: 0},
133 {.RegClass: 0, .Flags: 1 << MCOI::OptionalDef, .OperandType: MCOI::OPERAND_REGISTER, .Constraints: 0}}};
134
135 // Define a series of instructions with different kinds of operands and make
136 // sure that the hash function is consistent with isEqual for various
137 // combinations of them.
138 unsigned VirtualDef1 = -42;
139 unsigned VirtualDef2 = -43;
140 unsigned VirtualReg = -44;
141 unsigned SentinelReg = 0;
142 unsigned PhysicalReg = 45;
143
144 auto VD1VU = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
145 VD1VU->addOperand(MF&: *MF,
146 Op: MachineOperand::CreateReg(Reg: VirtualDef1, /*isDef*/ true));
147 VD1VU->addOperand(MF&: *MF,
148 Op: MachineOperand::CreateReg(Reg: VirtualReg, /*isDef*/ false));
149
150 auto VD2VU = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
151 VD2VU->addOperand(MF&: *MF,
152 Op: MachineOperand::CreateReg(Reg: VirtualDef2, /*isDef*/ true));
153 VD2VU->addOperand(MF&: *MF,
154 Op: MachineOperand::CreateReg(Reg: VirtualReg, /*isDef*/ false));
155
156 auto VD1SU = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
157 VD1SU->addOperand(MF&: *MF,
158 Op: MachineOperand::CreateReg(Reg: VirtualDef1, /*isDef*/ true));
159 VD1SU->addOperand(MF&: *MF,
160 Op: MachineOperand::CreateReg(Reg: SentinelReg, /*isDef*/ false));
161
162 auto VD1SD = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
163 VD1SD->addOperand(MF&: *MF,
164 Op: MachineOperand::CreateReg(Reg: VirtualDef1, /*isDef*/ true));
165 VD1SD->addOperand(MF&: *MF,
166 Op: MachineOperand::CreateReg(Reg: SentinelReg, /*isDef*/ true));
167
168 auto VD2PU = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
169 VD2PU->addOperand(MF&: *MF,
170 Op: MachineOperand::CreateReg(Reg: VirtualDef2, /*isDef*/ true));
171 VD2PU->addOperand(MF&: *MF,
172 Op: MachineOperand::CreateReg(Reg: PhysicalReg, /*isDef*/ false));
173
174 auto VD2PD = MF->CreateMachineInstr(MCID: Table.MCID, DL: DebugLoc());
175 VD2PD->addOperand(MF&: *MF,
176 Op: MachineOperand::CreateReg(Reg: VirtualDef2, /*isDef*/ true));
177 VD2PD->addOperand(MF&: *MF,
178 Op: MachineOperand::CreateReg(Reg: PhysicalReg, /*isDef*/ true));
179
180 checkHashAndIsEqualMatch(MI1: VD1VU, MI2: VD2VU);
181 checkHashAndIsEqualMatch(MI1: VD1VU, MI2: VD1SU);
182 checkHashAndIsEqualMatch(MI1: VD1VU, MI2: VD1SD);
183 checkHashAndIsEqualMatch(MI1: VD1VU, MI2: VD2PU);
184 checkHashAndIsEqualMatch(MI1: VD1VU, MI2: VD2PD);
185
186 checkHashAndIsEqualMatch(MI1: VD2VU, MI2: VD1SU);
187 checkHashAndIsEqualMatch(MI1: VD2VU, MI2: VD1SD);
188 checkHashAndIsEqualMatch(MI1: VD2VU, MI2: VD2PU);
189 checkHashAndIsEqualMatch(MI1: VD2VU, MI2: VD2PD);
190
191 checkHashAndIsEqualMatch(MI1: VD1SU, MI2: VD1SD);
192 checkHashAndIsEqualMatch(MI1: VD1SU, MI2: VD2PU);
193 checkHashAndIsEqualMatch(MI1: VD1SU, MI2: VD2PD);
194
195 checkHashAndIsEqualMatch(MI1: VD1SD, MI2: VD2PU);
196 checkHashAndIsEqualMatch(MI1: VD1SD, MI2: VD2PD);
197
198 checkHashAndIsEqualMatch(MI1: VD2PU, MI2: VD2PD);
199}
200
201TEST(MachineInstrPrintingTest, DebugLocPrinting) {
202 LLVMContext Ctx;
203 Module Mod("Module", Ctx);
204 auto MF = createMachineFunction(Ctx, M&: Mod);
205
206 struct {
207 MCInstrDesc MCID;
208 MCOperandInfo OpInfo;
209 } Table = {.MCID: {.Opcode: 0, .NumOperands: 1, .NumDefs: 1, .Size: 0, .SchedClass: 0, .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: 0, .TSFlags: 0},
210 .OpInfo: {.RegClass: 0, .Flags: 0, .OperandType: MCOI::OPERAND_REGISTER, .Constraints: 0}};
211
212 DIFile *DIF = DIFile::getDistinct(Context&: Ctx, Filename: "filename", Directory: "");
213 DISubprogram *DIS = DISubprogram::getDistinct(
214 Context&: Ctx, Scope: nullptr, Name: "", LinkageName: "", File: DIF, Line: 0, Type: nullptr, ScopeLine: 0, ContainingType: nullptr, VirtualIndex: 0, ThisAdjustment: 0, Flags: DINode::FlagZero,
215 SPFlags: DISubprogram::SPFlagZero, Unit: nullptr);
216 DILocation *DIL = DILocation::get(Context&: Ctx, Line: 1, Column: 5, Scope: DIS);
217 DebugLoc DL(DIL);
218 MachineInstr *MI = MF->CreateMachineInstr(MCID: Table.MCID, DL);
219 MI->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: 0, /*isDef*/ true));
220
221 std::string str;
222 raw_string_ostream OS(str);
223 MI->print(OS, /*IsStandalone*/true, /*SkipOpers*/false, /*SkipDebugLoc*/false,
224 /*AddNewLine*/false);
225 ASSERT_TRUE(
226 StringRef(OS.str()).starts_with("$noreg = UNKNOWN debug-location "));
227 ASSERT_TRUE(StringRef(OS.str()).ends_with("filename:1:5"));
228}
229
230TEST(MachineInstrSpan, DistanceBegin) {
231 LLVMContext Ctx;
232 Module Mod("Module", Ctx);
233 auto MF = createMachineFunction(Ctx, M&: Mod);
234 auto MBB = MF->CreateMachineBasicBlock();
235
236 MCInstrDesc MCID = {.Opcode: 0, .NumOperands: 0, .NumDefs: 0, .Size: 0, .SchedClass: 0, .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: 0, .TSFlags: 0};
237
238 auto MII = MBB->begin();
239 MachineInstrSpan MIS(MII, MBB);
240 ASSERT_TRUE(MIS.empty());
241
242 auto MI = MF->CreateMachineInstr(MCID, DL: DebugLoc());
243 MBB->insert(I: MII, MI);
244 ASSERT_TRUE(std::distance(MIS.begin(), MII) == 1);
245}
246
247TEST(MachineInstrSpan, DistanceEnd) {
248 LLVMContext Ctx;
249 Module Mod("Module", Ctx);
250 auto MF = createMachineFunction(Ctx, M&: Mod);
251 auto MBB = MF->CreateMachineBasicBlock();
252
253 MCInstrDesc MCID = {.Opcode: 0, .NumOperands: 0, .NumDefs: 0, .Size: 0, .SchedClass: 0, .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: 0, .TSFlags: 0};
254
255 auto MII = MBB->end();
256 MachineInstrSpan MIS(MII, MBB);
257 ASSERT_TRUE(MIS.empty());
258
259 auto MI = MF->CreateMachineInstr(MCID, DL: DebugLoc());
260 MBB->insert(I: MII, MI);
261 ASSERT_TRUE(std::distance(MIS.begin(), MII) == 1);
262}
263
264TEST(MachineInstrExtraInfo, AddExtraInfo) {
265 LLVMContext Ctx;
266 Module Mod("Module", Ctx);
267 auto MF = createMachineFunction(Ctx, M&: Mod);
268 MCInstrDesc MCID = {.Opcode: 0, .NumOperands: 0, .NumDefs: 0, .Size: 0, .SchedClass: 0, .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: 0, .TSFlags: 0};
269
270 auto MI = MF->CreateMachineInstr(MCID, DL: DebugLoc());
271 auto MAI = MCAsmInfo();
272 auto MC = createMCContext(AsmInfo: &MAI);
273 auto MMO = MF->getMachineMemOperand(PtrInfo: MachinePointerInfo(),
274 F: MachineMemOperand::MOLoad, Size: 8, BaseAlignment: Align(8));
275 SmallVector<MachineMemOperand *, 2> MMOs;
276 MMOs.push_back(Elt: MMO);
277 MCSymbol *Sym1 = MC->createTempSymbol(Name: "pre_label", AlwaysAddSuffix: false);
278 MCSymbol *Sym2 = MC->createTempSymbol(Name: "post_label", AlwaysAddSuffix: false);
279 MDNode *HAM = MDNode::getDistinct(Context&: Ctx, MDs: std::nullopt);
280 MDNode *PCS = MDNode::getDistinct(Context&: Ctx, MDs: std::nullopt);
281 MDNode *MMRA = MMRAMetadata::getTagMD(Ctx, Prefix: "foo", Suffix: "bar");
282
283 ASSERT_TRUE(MI->memoperands_empty());
284 ASSERT_FALSE(MI->getPreInstrSymbol());
285 ASSERT_FALSE(MI->getPostInstrSymbol());
286 ASSERT_FALSE(MI->getHeapAllocMarker());
287 ASSERT_FALSE(MI->getPCSections());
288 ASSERT_FALSE(MI->getMMRAMetadata());
289
290 MI->setMemRefs(MF&: *MF, MemRefs: MMOs);
291 ASSERT_TRUE(MI->memoperands().size() == 1);
292 ASSERT_FALSE(MI->getPreInstrSymbol());
293 ASSERT_FALSE(MI->getPostInstrSymbol());
294 ASSERT_FALSE(MI->getHeapAllocMarker());
295 ASSERT_FALSE(MI->getPCSections());
296 ASSERT_FALSE(MI->getMMRAMetadata());
297
298 MI->setPreInstrSymbol(MF&: *MF, Symbol: Sym1);
299 ASSERT_TRUE(MI->memoperands().size() == 1);
300 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
301 ASSERT_FALSE(MI->getPostInstrSymbol());
302 ASSERT_FALSE(MI->getHeapAllocMarker());
303 ASSERT_FALSE(MI->getPCSections());
304 ASSERT_FALSE(MI->getMMRAMetadata());
305
306 MI->setPostInstrSymbol(MF&: *MF, Symbol: Sym2);
307 ASSERT_TRUE(MI->memoperands().size() == 1);
308 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
309 ASSERT_TRUE(MI->getPostInstrSymbol() == Sym2);
310 ASSERT_FALSE(MI->getHeapAllocMarker());
311 ASSERT_FALSE(MI->getPCSections());
312 ASSERT_FALSE(MI->getMMRAMetadata());
313
314 MI->setHeapAllocMarker(MF&: *MF, MD: HAM);
315 ASSERT_TRUE(MI->memoperands().size() == 1);
316 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
317 ASSERT_TRUE(MI->getPostInstrSymbol() == Sym2);
318 ASSERT_TRUE(MI->getHeapAllocMarker() == HAM);
319 ASSERT_FALSE(MI->getPCSections());
320 ASSERT_FALSE(MI->getMMRAMetadata());
321
322 MI->setPCSections(MF&: *MF, MD: PCS);
323 ASSERT_TRUE(MI->memoperands().size() == 1);
324 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
325 ASSERT_TRUE(MI->getPostInstrSymbol() == Sym2);
326 ASSERT_TRUE(MI->getHeapAllocMarker() == HAM);
327 ASSERT_TRUE(MI->getPCSections() == PCS);
328 ASSERT_FALSE(MI->getMMRAMetadata());
329
330 MI->setMMRAMetadata(MF&: *MF, MMRAs: MMRA);
331 ASSERT_TRUE(MI->memoperands().size() == 1);
332 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
333 ASSERT_TRUE(MI->getPostInstrSymbol() == Sym2);
334 ASSERT_TRUE(MI->getHeapAllocMarker() == HAM);
335 ASSERT_TRUE(MI->getPCSections() == PCS);
336 ASSERT_TRUE(MI->getMMRAMetadata() == MMRA);
337
338 // Check with nothing but MMRAs.
339 MachineInstr *MMRAMI = MF->CreateMachineInstr(MCID, DL: DebugLoc());
340 ASSERT_FALSE(MMRAMI->getMMRAMetadata());
341 MMRAMI->setMMRAMetadata(MF&: *MF, MMRAs: MMRA);
342 ASSERT_TRUE(MMRAMI->getMMRAMetadata() == MMRA);
343}
344
345TEST(MachineInstrExtraInfo, ChangeExtraInfo) {
346 LLVMContext Ctx;
347 Module Mod("Module", Ctx);
348 auto MF = createMachineFunction(Ctx, M&: Mod);
349 MCInstrDesc MCID = {.Opcode: 0, .NumOperands: 0, .NumDefs: 0, .Size: 0, .SchedClass: 0, .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: 0, .TSFlags: 0};
350
351 auto MI = MF->CreateMachineInstr(MCID, DL: DebugLoc());
352 auto MAI = MCAsmInfo();
353 auto MC = createMCContext(AsmInfo: &MAI);
354 auto MMO = MF->getMachineMemOperand(PtrInfo: MachinePointerInfo(),
355 F: MachineMemOperand::MOLoad, Size: 8, BaseAlignment: Align(8));
356 SmallVector<MachineMemOperand *, 2> MMOs;
357 MMOs.push_back(Elt: MMO);
358 MCSymbol *Sym1 = MC->createTempSymbol(Name: "pre_label", AlwaysAddSuffix: false);
359 MCSymbol *Sym2 = MC->createTempSymbol(Name: "post_label", AlwaysAddSuffix: false);
360 MDNode *HAM = MDNode::getDistinct(Context&: Ctx, MDs: std::nullopt);
361 MDNode *PCS = MDNode::getDistinct(Context&: Ctx, MDs: std::nullopt);
362
363 MDNode *MMRA1 = MMRAMetadata::getTagMD(Ctx, Prefix: "foo", Suffix: "bar");
364 MDNode *MMRA2 = MMRAMetadata::getTagMD(Ctx, Prefix: "bar", Suffix: "bux");
365
366 MI->setMemRefs(MF&: *MF, MemRefs: MMOs);
367 MI->setPreInstrSymbol(MF&: *MF, Symbol: Sym1);
368 MI->setPostInstrSymbol(MF&: *MF, Symbol: Sym2);
369 MI->setHeapAllocMarker(MF&: *MF, MD: HAM);
370 MI->setPCSections(MF&: *MF, MD: PCS);
371 MI->setMMRAMetadata(MF&: *MF, MMRAs: MMRA1);
372
373 MMOs.push_back(Elt: MMO);
374
375 MI->setMemRefs(MF&: *MF, MemRefs: MMOs);
376 ASSERT_TRUE(MI->memoperands().size() == 2);
377 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
378 ASSERT_TRUE(MI->getPostInstrSymbol() == Sym2);
379 ASSERT_TRUE(MI->getHeapAllocMarker() == HAM);
380 ASSERT_TRUE(MI->getPCSections() == PCS);
381 ASSERT_TRUE(MI->getMMRAMetadata() == MMRA1);
382
383 MI->setPostInstrSymbol(MF&: *MF, Symbol: Sym1);
384 ASSERT_TRUE(MI->memoperands().size() == 2);
385 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
386 ASSERT_TRUE(MI->getPostInstrSymbol() == Sym1);
387 ASSERT_TRUE(MI->getHeapAllocMarker() == HAM);
388 ASSERT_TRUE(MI->getPCSections() == PCS);
389 ASSERT_TRUE(MI->getMMRAMetadata() == MMRA1);
390
391 MI->setMMRAMetadata(MF&: *MF, MMRAs: MMRA2);
392 ASSERT_TRUE(MI->memoperands().size() == 2);
393 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
394 ASSERT_TRUE(MI->getPostInstrSymbol() == Sym1);
395 ASSERT_TRUE(MI->getHeapAllocMarker() == HAM);
396 ASSERT_TRUE(MI->getPCSections() == PCS);
397 ASSERT_TRUE(MI->getMMRAMetadata() == MMRA2);
398}
399
400TEST(MachineInstrExtraInfo, RemoveExtraInfo) {
401 LLVMContext Ctx;
402 Module Mod("Module", Ctx);
403 auto MF = createMachineFunction(Ctx, M&: Mod);
404 MCInstrDesc MCID = {.Opcode: 0, .NumOperands: 0, .NumDefs: 0, .Size: 0, .SchedClass: 0, .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: 0, .TSFlags: 0};
405
406 auto MI = MF->CreateMachineInstr(MCID, DL: DebugLoc());
407 auto MAI = MCAsmInfo();
408 auto MC = createMCContext(AsmInfo: &MAI);
409 auto MMO = MF->getMachineMemOperand(PtrInfo: MachinePointerInfo(),
410 F: MachineMemOperand::MOLoad, Size: 8, BaseAlignment: Align(8));
411 SmallVector<MachineMemOperand *, 2> MMOs;
412 MMOs.push_back(Elt: MMO);
413 MMOs.push_back(Elt: MMO);
414 MCSymbol *Sym1 = MC->createTempSymbol(Name: "pre_label", AlwaysAddSuffix: false);
415 MCSymbol *Sym2 = MC->createTempSymbol(Name: "post_label", AlwaysAddSuffix: false);
416 MDNode *HAM = MDNode::getDistinct(Context&: Ctx, MDs: std::nullopt);
417 MDNode *PCS = MDNode::getDistinct(Context&: Ctx, MDs: std::nullopt);
418
419 MDNode *MMRA = MDTuple::get(Context&: Ctx, MDs: {});
420
421 MI->setMemRefs(MF&: *MF, MemRefs: MMOs);
422 MI->setPreInstrSymbol(MF&: *MF, Symbol: Sym1);
423 MI->setPostInstrSymbol(MF&: *MF, Symbol: Sym2);
424 MI->setHeapAllocMarker(MF&: *MF, MD: HAM);
425 MI->setPCSections(MF&: *MF, MD: PCS);
426 MI->setMMRAMetadata(MF&: *MF, MMRAs: MMRA);
427
428 MI->setPostInstrSymbol(MF&: *MF, Symbol: nullptr);
429 ASSERT_TRUE(MI->memoperands().size() == 2);
430 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
431 ASSERT_FALSE(MI->getPostInstrSymbol());
432 ASSERT_TRUE(MI->getHeapAllocMarker() == HAM);
433 ASSERT_TRUE(MI->getPCSections() == PCS);
434 ASSERT_TRUE(MI->getMMRAMetadata() == MMRA);
435
436 MI->setHeapAllocMarker(MF&: *MF, MD: nullptr);
437 ASSERT_TRUE(MI->memoperands().size() == 2);
438 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
439 ASSERT_FALSE(MI->getPostInstrSymbol());
440 ASSERT_FALSE(MI->getHeapAllocMarker());
441 ASSERT_TRUE(MI->getPCSections() == PCS);
442 ASSERT_TRUE(MI->getMMRAMetadata() == MMRA);
443
444 MI->setPCSections(MF&: *MF, MD: nullptr);
445 ASSERT_TRUE(MI->memoperands().size() == 2);
446 ASSERT_TRUE(MI->getPreInstrSymbol() == Sym1);
447 ASSERT_FALSE(MI->getPostInstrSymbol());
448 ASSERT_FALSE(MI->getHeapAllocMarker());
449 ASSERT_FALSE(MI->getPCSections());
450 ASSERT_TRUE(MI->getMMRAMetadata() == MMRA);
451
452 MI->setPreInstrSymbol(MF&: *MF, Symbol: nullptr);
453 ASSERT_TRUE(MI->memoperands().size() == 2);
454 ASSERT_FALSE(MI->getPreInstrSymbol());
455 ASSERT_FALSE(MI->getPostInstrSymbol());
456 ASSERT_FALSE(MI->getHeapAllocMarker());
457 ASSERT_FALSE(MI->getPCSections());
458 ASSERT_TRUE(MI->getMMRAMetadata() == MMRA);
459
460 MI->setMemRefs(MF&: *MF, MemRefs: {});
461 ASSERT_TRUE(MI->memoperands_empty());
462 ASSERT_FALSE(MI->getPreInstrSymbol());
463 ASSERT_FALSE(MI->getPostInstrSymbol());
464 ASSERT_FALSE(MI->getHeapAllocMarker());
465 ASSERT_FALSE(MI->getPCSections());
466 ASSERT_TRUE(MI->getMMRAMetadata() == MMRA);
467
468 MI->setMMRAMetadata(MF&: *MF, MMRAs: nullptr);
469 ASSERT_TRUE(MI->memoperands_empty());
470 ASSERT_FALSE(MI->getPreInstrSymbol());
471 ASSERT_FALSE(MI->getPostInstrSymbol());
472 ASSERT_FALSE(MI->getHeapAllocMarker());
473 ASSERT_FALSE(MI->getPCSections());
474 ASSERT_FALSE(MI->getMMRAMetadata());
475}
476
477TEST(MachineInstrDebugValue, AddDebugValueOperand) {
478 LLVMContext Ctx;
479 Module Mod("Module", Ctx);
480 auto MF = createMachineFunction(Ctx, M&: Mod);
481
482 for (const unsigned short Opcode :
483 {TargetOpcode::DBG_VALUE, TargetOpcode::DBG_VALUE_LIST,
484 TargetOpcode::DBG_INSTR_REF, TargetOpcode::DBG_PHI,
485 TargetOpcode::DBG_LABEL}) {
486 const MCInstrDesc MCID = {
487 .Opcode: Opcode, .NumOperands: 0, .NumDefs: 0, .Size: 0, .SchedClass: 0,
488 .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: (1ULL << MCID::Pseudo) | (1ULL << MCID::Variadic),
489 .TSFlags: 0};
490
491 auto *MI = MF->CreateMachineInstr(MCID, DL: DebugLoc());
492 MI->addOperand(MF&: *MF, Op: MachineOperand::CreateReg(Reg: 0, /*isDef*/ false));
493
494 MI->addOperand(MF&: *MF, Op: MachineOperand::CreateImm(Val: 0));
495 MI->getOperand(i: 1).ChangeToRegister(Reg: 0, isDef: false);
496
497 ASSERT_TRUE(MI->getOperand(0).isDebug());
498 ASSERT_TRUE(MI->getOperand(1).isDebug());
499 }
500}
501
502MATCHER_P(HasMIMetadata, MIMD, "") {
503 return arg->getDebugLoc() == MIMD.getDL() &&
504 arg->getPCSections() == MIMD.getPCSections();
505}
506
507TEST(MachineInstrBuilder, BuildMI) {
508 LLVMContext Ctx;
509 MDNode *PCS = MDNode::getDistinct(Context&: Ctx, MDs: std::nullopt);
510 MDNode *DI = MDNode::getDistinct(Context&: Ctx, MDs: std::nullopt);
511 DebugLoc DL(DI);
512 MIMetadata MIMD(DL, PCS);
513 EXPECT_EQ(MIMD.getDL(), DL);
514 EXPECT_EQ(MIMD.getPCSections(), PCS);
515 // Check common BuildMI() overloads propagate MIMetadata.
516 Module Mod("Module", Ctx);
517 auto MF = createMachineFunction(Ctx, M&: Mod);
518 auto MBB = MF->CreateMachineBasicBlock();
519 MCInstrDesc MCID = {.Opcode: 0, .NumOperands: 0, .NumDefs: 0, .Size: 0, .SchedClass: 0, .NumImplicitUses: 0, .NumImplicitDefs: 0, .ImplicitOffset: 0, .OpInfoOffset: 0, .Flags: 0, .TSFlags: 0};
520 EXPECT_THAT(BuildMI(*MF, MIMD, MCID), HasMIMetadata(MIMD));
521 EXPECT_THAT(BuildMI(*MF, MIMD, MCID), HasMIMetadata(MIMD));
522 EXPECT_THAT(BuildMI(*MBB, MBB->end(), MIMD, MCID), HasMIMetadata(MIMD));
523 EXPECT_THAT(BuildMI(*MBB, MBB->end(), MIMD, MCID), HasMIMetadata(MIMD));
524 EXPECT_THAT(BuildMI(*MBB, MBB->instr_end(), MIMD, MCID), HasMIMetadata(MIMD));
525 EXPECT_THAT(BuildMI(*MBB, *MBB->begin(), MIMD, MCID), HasMIMetadata(MIMD));
526 EXPECT_THAT(BuildMI(*MBB, &*MBB->begin(), MIMD, MCID), HasMIMetadata(MIMD));
527 EXPECT_THAT(BuildMI(MBB, MIMD, MCID), HasMIMetadata(MIMD));
528}
529
530static_assert(std::is_trivially_copyable_v<MCOperand>, "trivially copyable");
531
532TEST(MachineInstrTest, SpliceOperands) {
533 LLVMContext Ctx;
534 Module Mod("Module", Ctx);
535 std::unique_ptr<MachineFunction> MF = createMachineFunction(Ctx, M&: Mod);
536 MachineBasicBlock *MBB = MF->CreateMachineBasicBlock();
537 MCInstrDesc MCID = {.Opcode: TargetOpcode::INLINEASM,
538 .NumOperands: 0,
539 .NumDefs: 0,
540 .Size: 0,
541 .SchedClass: 0,
542 .NumImplicitUses: 0,
543 .NumImplicitDefs: 0,
544 .ImplicitOffset: 0,
545 .OpInfoOffset: 0,
546 .Flags: (1ULL << MCID::Pseudo) | (1ULL << MCID::Variadic),
547 .TSFlags: 0};
548 MachineInstr *MI = MF->CreateMachineInstr(MCID, DL: DebugLoc());
549 MBB->insert(I: MBB->begin(), MI);
550 MI->addOperand(Op: MachineOperand::CreateImm(Val: 0));
551 MI->addOperand(Op: MachineOperand::CreateImm(Val: 1));
552 MI->addOperand(Op: MachineOperand::CreateImm(Val: 2));
553 MI->addOperand(Op: MachineOperand::CreateImm(Val: 3));
554 MI->addOperand(Op: MachineOperand::CreateImm(Val: 4));
555
556 MI->removeOperand(OpNo: 1);
557 EXPECT_EQ(MI->getOperand(1).getImm(), MachineOperand::CreateImm(2).getImm());
558 EXPECT_EQ(MI->getNumOperands(), 4U);
559
560 MachineOperand Ops[] = {
561 MachineOperand::CreateImm(Val: 42), MachineOperand::CreateImm(Val: 1024),
562 MachineOperand::CreateImm(Val: 2048), MachineOperand::CreateImm(Val: 4096),
563 MachineOperand::CreateImm(Val: 8192),
564 };
565 auto *It = MI->operands_begin();
566 ++It;
567 MI->insert(InsertBefore: It, Ops);
568
569 EXPECT_EQ(MI->getNumOperands(), 9U);
570 EXPECT_EQ(MI->getOperand(0).getImm(), MachineOperand::CreateImm(0).getImm());
571 EXPECT_EQ(MI->getOperand(1).getImm(), MachineOperand::CreateImm(42).getImm());
572 EXPECT_EQ(MI->getOperand(2).getImm(),
573 MachineOperand::CreateImm(1024).getImm());
574 EXPECT_EQ(MI->getOperand(3).getImm(),
575 MachineOperand::CreateImm(2048).getImm());
576 EXPECT_EQ(MI->getOperand(4).getImm(),
577 MachineOperand::CreateImm(4096).getImm());
578 EXPECT_EQ(MI->getOperand(5).getImm(),
579 MachineOperand::CreateImm(8192).getImm());
580 EXPECT_EQ(MI->getOperand(6).getImm(), MachineOperand::CreateImm(2).getImm());
581 EXPECT_EQ(MI->getOperand(7).getImm(), MachineOperand::CreateImm(3).getImm());
582 EXPECT_EQ(MI->getOperand(8).getImm(), MachineOperand::CreateImm(4).getImm());
583
584 // test tied operands
585 MCRegisterClass MRC{
586 .RegsBegin: 0, .RegSet: 0, .NameIdx: 0, .RegsSize: 0, .RegSetSize: 0, .ID: 0, .RegSizeInBits: 0, .CopyCost: 0, /*Allocatable=*/true, /*BaseClass=*/true};
587 TargetRegisterClass RC{.MC: &MRC, .SubClassMask: 0, .SuperRegIndices: 0, .LaneMask: {}, .AllocationPriority: 0, .GlobalPriority: 0, .TSFlags: 0, .HasDisjunctSubRegs: 0, .CoveredBySubRegs: 0, .SuperClasses: 0, .OrderFunc: 0};
588 // MachineRegisterInfo will be very upset if these registers aren't
589 // allocatable.
590 assert(RC.isAllocatable() && "unusable TargetRegisterClass");
591 MachineRegisterInfo &MRI = MF->getRegInfo();
592 Register A = MRI.createVirtualRegister(RegClass: &RC);
593 Register B = MRI.createVirtualRegister(RegClass: &RC);
594 MI->getOperand(i: 0).ChangeToRegister(Reg: A, /*isDef=*/true);
595 MI->getOperand(i: 1).ChangeToRegister(Reg: B, /*isDef=*/false);
596 MI->tieOperands(DefIdx: 0, UseIdx: 1);
597 EXPECT_TRUE(MI->getOperand(0).isTied());
598 EXPECT_TRUE(MI->getOperand(1).isTied());
599 EXPECT_EQ(MI->findTiedOperandIdx(0), 1U);
600 EXPECT_EQ(MI->findTiedOperandIdx(1), 0U);
601 MI->insert(InsertBefore: &MI->getOperand(i: 1), Ops: {MachineOperand::CreateImm(Val: 7)});
602 EXPECT_TRUE(MI->getOperand(0).isTied());
603 EXPECT_TRUE(MI->getOperand(1).isImm());
604 EXPECT_TRUE(MI->getOperand(2).isTied());
605 EXPECT_EQ(MI->findTiedOperandIdx(0), 2U);
606 EXPECT_EQ(MI->findTiedOperandIdx(2), 0U);
607 EXPECT_EQ(MI->getOperand(0).getReg(), A);
608 EXPECT_EQ(MI->getOperand(2).getReg(), B);
609
610 // bad inputs
611 EXPECT_EQ(MI->getNumOperands(), 10U);
612 MI->insert(InsertBefore: MI->operands_begin(), Ops: {});
613 EXPECT_EQ(MI->getNumOperands(), 10U);
614}
615
616} // end namespace
617

source code of llvm/unittests/CodeGen/MachineInstrTest.cpp