LLVM 24.0.0git
SIPeepholeSDWA.cpp
Go to the documentation of this file.
1//===- SIPeepholeSDWA.cpp - Peephole optimization for SDWA instructions ---===//
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/// \file This pass tries to apply several peephole SDWA patterns.
10///
11/// E.g. original:
12/// V_LSHRREV_B32_e32 %0, 16, %1
13/// V_ADD_CO_U32_e32 %2, %0, %3
14/// V_LSHLREV_B32_e32 %4, 16, %2
15///
16/// Replace:
17/// V_ADD_CO_U32_sdwa %4, %1, %3
18/// dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:DWORD
19///
20//===----------------------------------------------------------------------===//
21
22#include "SIPeepholeSDWA.h"
23#include "AMDGPU.h"
24#include "GCNSubtarget.h"
26#include "llvm/ADT/MapVector.h"
27#include "llvm/ADT/Statistic.h"
30#include <optional>
31
32using namespace llvm;
33
34#define DEBUG_TYPE "si-peephole-sdwa"
35
36STATISTIC(NumSDWAPatternsFound, "Number of SDWA patterns found.");
37STATISTIC(NumSDWAInstructionsPeepholed,
38 "Number of instruction converted to SDWA.");
39
40namespace {
41
42bool isConvertibleToSDWA(MachineInstr &MI, const GCNSubtarget &ST,
43 const SIInstrInfo *TII);
44class SDWAOperand;
45class SDWADstOperand;
46
47using SDWAOperandsVector = SmallVector<SDWAOperand *, 4>;
49
50class SIPeepholeSDWA {
51private:
53 const SIRegisterInfo *TRI;
54 const SIInstrInfo *TII;
55
57 SDWAOperandsMap PotentialMatches;
58 SmallVector<MachineInstr *, 8> ConvertedInstructions;
59
60 std::optional<int64_t> foldToImm(const MachineOperand &Op) const;
61
62 // If MI is a v_and_b32 with a 0xffff or 0xff immediate, return the masked
63 // value operand and the matching SDWA selector (WORD_0 / BYTE_0).
64 std::optional<std::pair<MachineOperand *, AMDGPU::SDWA::SdwaSel>>
65 matchAndMask(MachineInstr &MI) const;
66
67 // VOPC SDWA instructions carry the SDWA TSFlag but have no dst_sel operand.
68 bool isSDWAWithDstSel(const MachineInstr &Inst) const;
69
70 void matchSDWAOperands(MachineBasicBlock &MBB);
71 std::unique_ptr<SDWAOperand> matchSDWAOperand(MachineInstr &MI);
72 void pseudoOpConvertToVOP2(MachineInstr &MI,
73 const GCNSubtarget &ST) const;
74 void convertVcndmaskToVOP2(MachineInstr &MI, const GCNSubtarget &ST) const;
75 MachineInstr *createSDWAVersion(MachineInstr &MI);
76 bool convertToSDWA(MachineInstr &MI, const SDWAOperandsVector &SDWAOperands);
77 void legalizeScalarOperands(MachineInstr &MI, const GCNSubtarget &ST) const;
78 bool splitLshlOrForSDWA(MachineBasicBlock &MBB);
79
80public:
81 bool run(MachineFunction &MF);
82};
83
84class SIPeepholeSDWALegacy : public MachineFunctionPass {
85public:
86 static char ID;
87
88 SIPeepholeSDWALegacy() : MachineFunctionPass(ID) {}
89
90 StringRef getPassName() const override { return "SI Peephole SDWA"; }
91
92 bool runOnMachineFunction(MachineFunction &MF) override;
93
94 void getAnalysisUsage(AnalysisUsage &AU) const override {
95 AU.setPreservesCFG();
97 }
98};
99
100using namespace AMDGPU::SDWA;
101
102class SDWAOperand {
103private:
104 MachineOperand *Target; // Operand that would be used in converted instruction
105 MachineOperand *Replaced; // Operand that would be replace by Target
106
107 /// Returns true iff the SDWA selection of this SDWAOperand can be combined
108 /// with the SDWA selections of its uses in \p MI.
109 virtual bool canCombineSelections(const MachineInstr &MI,
110 const SIInstrInfo *TII) = 0;
111
112public:
113 SDWAOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp)
114 : Target(TargetOp), Replaced(ReplacedOp) {
115 assert(Target->isReg());
116 assert(Replaced->isReg());
117 }
118
119 virtual ~SDWAOperand() = default;
120
121 virtual MachineInstr *potentialToConvert(const SIInstrInfo *TII,
122 const GCNSubtarget &ST,
123 SDWAOperandsMap *PotentialMatches = nullptr) = 0;
124 virtual bool convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) = 0;
125
126 MachineOperand *getTargetOperand() const { return Target; }
127 MachineOperand *getReplacedOperand() const { return Replaced; }
128 MachineInstr *getParentInst() const { return Target->getParent(); }
129
130 MachineRegisterInfo *getMRI() const {
131 return &getParentInst()->getMF()->getRegInfo();
132 }
133
134#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
135 virtual void print(raw_ostream& OS) const = 0;
136 void dump() const { print(dbgs()); }
137#endif
138};
139
140class SDWASrcOperand : public SDWAOperand {
141private:
142 SdwaSel SrcSel;
143 bool Abs;
144 bool Neg;
145 bool Sext;
146
147public:
148 SDWASrcOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
149 SdwaSel SrcSel_ = DWORD, bool Abs_ = false, bool Neg_ = false,
150 bool Sext_ = false)
151 : SDWAOperand(TargetOp, ReplacedOp), SrcSel(SrcSel_), Abs(Abs_),
152 Neg(Neg_), Sext(Sext_) {}
153
154 MachineInstr *potentialToConvert(const SIInstrInfo *TII,
155 const GCNSubtarget &ST,
156 SDWAOperandsMap *PotentialMatches = nullptr) override;
157 bool convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) override;
158 bool canCombineSelections(const MachineInstr &MI,
159 const SIInstrInfo *TII) override;
160
161 SdwaSel getSrcSel() const { return SrcSel; }
162 bool getAbs() const { return Abs; }
163 bool getNeg() const { return Neg; }
164 bool getSext() const { return Sext; }
165
166 uint64_t getSrcMods(const SIInstrInfo *TII,
167 const MachineOperand *SrcOp) const;
168
169#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
170 void print(raw_ostream& OS) const override;
171#endif
172};
173
174class SDWADstOperand : public SDWAOperand {
175private:
176 SdwaSel DstSel;
177 DstUnused DstUn;
178
179public:
180 SDWADstOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
181 SdwaSel DstSel_ = DWORD, DstUnused DstUn_ = UNUSED_PAD)
182 : SDWAOperand(TargetOp, ReplacedOp), DstSel(DstSel_), DstUn(DstUn_) {}
183
184 MachineInstr *potentialToConvert(const SIInstrInfo *TII,
185 const GCNSubtarget &ST,
186 SDWAOperandsMap *PotentialMatches = nullptr) override;
187 bool convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) override;
188 bool canCombineSelections(const MachineInstr &MI,
189 const SIInstrInfo *TII) override;
190
191 SdwaSel getDstSel() const { return DstSel; }
192 DstUnused getDstUnused() const { return DstUn; }
193
194#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
195 void print(raw_ostream& OS) const override;
196#endif
197};
198
199class SDWADstPreserveOperand : public SDWADstOperand {
200private:
201 MachineOperand *Preserve;
202
203public:
204 SDWADstPreserveOperand(MachineOperand *TargetOp, MachineOperand *ReplacedOp,
205 MachineOperand *PreserveOp, SdwaSel DstSel_ = DWORD)
206 : SDWADstOperand(TargetOp, ReplacedOp, DstSel_, UNUSED_PRESERVE),
207 Preserve(PreserveOp) {}
208
209 bool convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) override;
210 bool canCombineSelections(const MachineInstr &MI,
211 const SIInstrInfo *TII) override;
212
213 MachineOperand *getPreservedOperand() const { return Preserve; }
214
215#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
216 void print(raw_ostream& OS) const override;
217#endif
218};
219
220} // end anonymous namespace
221
222INITIALIZE_PASS(SIPeepholeSDWALegacy, DEBUG_TYPE, "SI Peephole SDWA", false,
223 false)
224
225char SIPeepholeSDWALegacy::ID = 0;
226
227char &llvm::SIPeepholeSDWALegacyID = SIPeepholeSDWALegacy::ID;
228
230 return new SIPeepholeSDWALegacy();
231}
232
233#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
235 switch(Sel) {
236 case BYTE_0: OS << "BYTE_0"; break;
237 case BYTE_1: OS << "BYTE_1"; break;
238 case BYTE_2: OS << "BYTE_2"; break;
239 case BYTE_3: OS << "BYTE_3"; break;
240 case WORD_0: OS << "WORD_0"; break;
241 case WORD_1: OS << "WORD_1"; break;
242 case DWORD: OS << "DWORD"; break;
243 }
244 return OS;
245}
246
248 switch(Un) {
249 case UNUSED_PAD: OS << "UNUSED_PAD"; break;
250 case UNUSED_SEXT: OS << "UNUSED_SEXT"; break;
251 case UNUSED_PRESERVE: OS << "UNUSED_PRESERVE"; break;
252 }
253 return OS;
254}
255
257void SDWASrcOperand::print(raw_ostream& OS) const {
258 OS << "SDWA src: " << *getTargetOperand()
259 << " src_sel:" << getSrcSel()
260 << " abs:" << getAbs() << " neg:" << getNeg()
261 << " sext:" << getSext() << '\n';
262}
263
265void SDWADstOperand::print(raw_ostream& OS) const {
266 OS << "SDWA dst: " << *getTargetOperand()
267 << " dst_sel:" << getDstSel()
268 << " dst_unused:" << getDstUnused() << '\n';
269}
270
272void SDWADstPreserveOperand::print(raw_ostream& OS) const {
273 OS << "SDWA preserve dst: " << *getTargetOperand()
274 << " dst_sel:" << getDstSel()
275 << " preserve:" << *getPreservedOperand() << '\n';
276}
277
278#endif
279
280static void copyRegOperand(MachineOperand &To, const MachineOperand &From) {
281 assert(To.isReg() && From.isReg());
282 To.setReg(From.getReg());
283 To.setSubReg(From.getSubReg());
284 To.setIsUndef(From.isUndef());
285 if (To.isUse()) {
286 To.setIsKill(From.isKill());
287 } else {
288 To.setIsDead(From.isDead());
289 }
290}
291
292static bool isSameReg(const MachineOperand &LHS, const MachineOperand &RHS) {
293 return LHS.isReg() &&
294 RHS.isReg() &&
295 LHS.getReg() == RHS.getReg() &&
296 LHS.getSubReg() == RHS.getSubReg();
297}
298
300 const MachineRegisterInfo *MRI) {
301 if (!Reg->isReg() || !Reg->isDef())
302 return nullptr;
303
304 return MRI->getOneNonDBGUse(Reg->getReg());
305}
306
308 const MachineRegisterInfo *MRI) {
309 if (!Reg->isReg())
310 return nullptr;
311
312 return MRI->getOneDef(Reg->getReg());
313}
314
315/// Combine an SDWA instruction's existing SDWA selection \p Sel with
316/// the SDWA selection \p OperandSel of its operand. If the selections
317/// are compatible, return the combined selection, otherwise return a
318/// nullopt.
319/// For example, if we have Sel = BYTE_0 Sel and OperandSel = WORD_1:
320/// BYTE_0 Sel (WORD_1 Sel (%X)) -> BYTE_2 Sel (%X)
321static std::optional<SdwaSel> combineSdwaSel(SdwaSel Sel, SdwaSel OperandSel) {
322 if (Sel == SdwaSel::DWORD)
323 return OperandSel;
324
325 if (Sel == OperandSel || OperandSel == SdwaSel::DWORD)
326 return Sel;
327
328 if (Sel == SdwaSel::WORD_1 || Sel == SdwaSel::BYTE_2 ||
329 Sel == SdwaSel::BYTE_3)
330 return {};
331
332 if (OperandSel == SdwaSel::WORD_0)
333 return Sel;
334
335 if (OperandSel == SdwaSel::WORD_1) {
336 if (Sel == SdwaSel::BYTE_0)
337 return SdwaSel::BYTE_2;
338 if (Sel == SdwaSel::BYTE_1)
339 return SdwaSel::BYTE_3;
340 if (Sel == SdwaSel::WORD_0)
341 return SdwaSel::WORD_1;
342 }
343
344 return {};
345}
346
347uint64_t SDWASrcOperand::getSrcMods(const SIInstrInfo *TII,
348 const MachineOperand *SrcOp) const {
349 uint64_t Mods = 0;
350 const auto *MI = SrcOp->getParent();
351 if (TII->getNamedOperand(*MI, AMDGPU::OpName::src0) == SrcOp) {
352 if (auto *Mod = TII->getNamedOperand(*MI, AMDGPU::OpName::src0_modifiers)) {
353 Mods = Mod->getImm();
354 }
355 } else if (TII->getNamedOperand(*MI, AMDGPU::OpName::src1) == SrcOp) {
356 if (auto *Mod = TII->getNamedOperand(*MI, AMDGPU::OpName::src1_modifiers)) {
357 Mods = Mod->getImm();
358 }
359 }
360 if (Abs || Neg) {
361 assert(!Sext &&
362 "Float and integer src modifiers can't be set simultaneously");
363 Mods |= Abs ? SISrcMods::ABS : 0u;
364 Mods ^= Neg ? SISrcMods::NEG : 0u;
365 } else if (Sext) {
366 Mods |= SISrcMods::SEXT;
367 }
368
369 return Mods;
370}
371
372MachineInstr *SDWASrcOperand::potentialToConvert(const SIInstrInfo *TII,
373 const GCNSubtarget &ST,
374 SDWAOperandsMap *PotentialMatches) {
375 if (PotentialMatches != nullptr) {
376 // Fill out the map for all uses if all can be converted
377 MachineOperand *Reg = getReplacedOperand();
378 if (!Reg->isReg() || !Reg->isDef())
379 return nullptr;
380
381 for (MachineInstr &UseMI : getMRI()->use_nodbg_instructions(Reg->getReg()))
382 // Check that all instructions that use Reg can be converted
383 if (!isConvertibleToSDWA(UseMI, ST, TII) ||
384 !canCombineSelections(UseMI, TII))
385 return nullptr;
386
387 // Now that it's guaranteed all uses are legal, iterate over the uses again
388 // to add them for later conversion.
389 for (MachineOperand &UseMO : getMRI()->use_nodbg_operands(Reg->getReg())) {
390 // Should not get a subregister here
391 assert(isSameReg(UseMO, *Reg));
392
393 SDWAOperandsMap &potentialMatchesMap = *PotentialMatches;
394 MachineInstr *UseMI = UseMO.getParent();
395 potentialMatchesMap[UseMI].push_back(this);
396 }
397 return nullptr;
398 }
399
400 // For SDWA src operand potential instruction is one that use register
401 // defined by parent instruction
402 MachineOperand *PotentialMO = findSingleRegUse(getReplacedOperand(), getMRI());
403 if (!PotentialMO)
404 return nullptr;
405
406 MachineInstr *Parent = PotentialMO->getParent();
407
408 return canCombineSelections(*Parent, TII) ? Parent : nullptr;
409}
410
411bool SDWASrcOperand::convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) {
412 assert((!Sext || !TII->getSubtarget().zeroesHigh16BitsOfDest(
413 getParentInst()->getOpcode())) &&
414 "Cannot use sign-extension with instruction that zeroes high bits");
415 switch (MI.getOpcode()) {
416 case AMDGPU::V_CVT_F32_FP8_sdwa:
417 case AMDGPU::V_CVT_F32_BF8_sdwa:
418 case AMDGPU::V_CVT_PK_F32_FP8_sdwa:
419 case AMDGPU::V_CVT_PK_F32_BF8_sdwa:
420 // Does not support input modifiers: noabs, noneg, nosext.
421 return false;
422 case AMDGPU::V_CNDMASK_B32_sdwa:
423 // SISrcMods uses the same bitmask for SEXT and NEG modifiers and
424 // hence the compiler can only support one type of modifier for
425 // each SDWA instruction. For V_CNDMASK_B32_sdwa, this is NEG
426 // since its operands get printed using
427 // AMDGPUInstPrinter::printOperandAndFPInputMods which produces
428 // the output intended for NEG if SEXT is set.
429 //
430 // The ISA does actually support both modifiers on most SDWA
431 // instructions.
432 //
433 // FIXME Accept SEXT here after fixing this issue.
434 if (Sext)
435 return false;
436 break;
437 }
438
439 // Find operand in instruction that matches source operand and replace it with
440 // target operand. Set corresponding src_sel
441 bool IsPreserveSrc = false;
442 MachineOperand *Src = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
443 MachineOperand *SrcSel = TII->getNamedOperand(MI, AMDGPU::OpName::src0_sel);
444 MachineOperand *SrcMods =
445 TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers);
446 assert(Src && (Src->isReg() || Src->isImm()));
447 if (!isSameReg(*Src, *getReplacedOperand())) {
448 // If this is not src0 then it could be src1
449 Src = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
450 SrcSel = TII->getNamedOperand(MI, AMDGPU::OpName::src1_sel);
451 SrcMods = TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers);
452
453 if (!Src ||
454 !isSameReg(*Src, *getReplacedOperand())) {
455 // It's possible this Src is a tied operand for
456 // UNUSED_PRESERVE, in which case we can either
457 // abandon the peephole attempt, or if legal we can
458 // copy the target operand into the tied slot
459 // if the preserve operation will effectively cause the same
460 // result by overwriting the rest of the dst.
461 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
462 MachineOperand *DstUnused =
463 TII->getNamedOperand(MI, AMDGPU::OpName::dst_unused);
464
465 if (Dst &&
466 DstUnused->getImm() == AMDGPU::SDWA::DstUnused::UNUSED_PRESERVE) {
467 // This will work if the tied src is accessing WORD_0, and the dst is
468 // writing WORD_1. Modifiers don't matter because all the bits that
469 // would be impacted are being overwritten by the dst.
470 // Any other case will not work.
471 SdwaSel DstSel = static_cast<SdwaSel>(
472 TII->getNamedImmOperand(MI, AMDGPU::OpName::dst_sel));
473 if (DstSel == AMDGPU::SDWA::SdwaSel::WORD_1 &&
474 getSrcSel() == AMDGPU::SDWA::SdwaSel::WORD_0) {
475 IsPreserveSrc = true;
476 auto DstIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(),
477 AMDGPU::OpName::vdst);
478 auto TiedIdx = MI.findTiedOperandIdx(DstIdx);
479 Src = &MI.getOperand(TiedIdx);
480 SrcSel = nullptr;
481 SrcMods = nullptr;
482 } else {
483 // Not legal to convert this src
484 return false;
485 }
486 }
487 }
488 assert(Src && Src->isReg());
489
490 if ((MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
491 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
492 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
493 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
494 !isSameReg(*Src, *getReplacedOperand())) {
495 // In case of v_mac_f16/32_sdwa this pass can try to apply src operand to
496 // src2. This is not allowed.
497 return false;
498 }
499
500 assert(isSameReg(*Src, *getReplacedOperand()) &&
501 (IsPreserveSrc || (SrcSel && SrcMods)));
502 }
503 copyRegOperand(*Src, *getTargetOperand());
504 if (!IsPreserveSrc) {
505 SdwaSel ExistingSel = static_cast<SdwaSel>(SrcSel->getImm());
506 SrcSel->setImm(*combineSdwaSel(ExistingSel, getSrcSel()));
507 SrcMods->setImm(getSrcMods(TII, Src));
508 }
509 getTargetOperand()->setIsKill(false);
510 return true;
511}
512
513/// Verify that the SDWA selection operand \p SrcSelOpName of the SDWA
514/// instruction \p MI can be combined with the selection \p OpSel.
515static bool canCombineOpSel(const MachineInstr &MI, const SIInstrInfo *TII,
516 AMDGPU::OpName SrcSelOpName, SdwaSel OpSel) {
517 assert(TII->isSDWA(MI.getOpcode()));
518
519 const MachineOperand *SrcSelOp = TII->getNamedOperand(MI, SrcSelOpName);
520 SdwaSel SrcSel = static_cast<SdwaSel>(SrcSelOp->getImm());
521
522 return combineSdwaSel(SrcSel, OpSel).has_value();
523}
524
525/// Verify that \p Op is the same register as the operand of the SDWA
526/// instruction \p MI named by \p SrcOpName and that the SDWA
527/// selection \p SrcSelOpName can be combined with the \p OpSel.
528static bool canCombineOpSel(const MachineInstr &MI, const SIInstrInfo *TII,
529 AMDGPU::OpName SrcOpName,
530 AMDGPU::OpName SrcSelOpName, MachineOperand *Op,
531 SdwaSel OpSel) {
532 assert(TII->isSDWA(MI.getOpcode()));
533
534 const MachineOperand *Src = TII->getNamedOperand(MI, SrcOpName);
535 if (!Src || !isSameReg(*Src, *Op))
536 return true;
537
538 return canCombineOpSel(MI, TII, SrcSelOpName, OpSel);
539}
540
541bool SDWASrcOperand::canCombineSelections(const MachineInstr &MI,
542 const SIInstrInfo *TII) {
543 if (!TII->isSDWA(MI.getOpcode()))
544 return true;
545
546 using namespace AMDGPU;
547
548 return canCombineOpSel(MI, TII, OpName::src0, OpName::src0_sel,
549 getReplacedOperand(), getSrcSel()) &&
550 canCombineOpSel(MI, TII, OpName::src1, OpName::src1_sel,
551 getReplacedOperand(), getSrcSel());
552}
553
554MachineInstr *SDWADstOperand::potentialToConvert(const SIInstrInfo *TII,
555 const GCNSubtarget &ST,
556 SDWAOperandsMap *PotentialMatches) {
557 // For SDWA dst operand potential instruction is one that defines register
558 // that this operand uses
559 MachineRegisterInfo *MRI = getMRI();
560 MachineInstr *ParentMI = getParentInst();
561
562 MachineOperand *PotentialMO = findSingleRegDef(getReplacedOperand(), MRI);
563 if (!PotentialMO)
564 return nullptr;
565
566 // Check that ParentMI is the only instruction that uses replaced register
567 for (MachineInstr &UseInst : MRI->use_nodbg_instructions(PotentialMO->getReg())) {
568 if (&UseInst != ParentMI)
569 return nullptr;
570 }
571
572 MachineInstr *Parent = PotentialMO->getParent();
573 return canCombineSelections(*Parent, TII) ? Parent : nullptr;
574}
575
576bool SDWADstOperand::convertToSDWA(MachineInstr &MI, const SIInstrInfo *TII) {
577 // Replace vdst operand in MI with target operand. Set dst_sel and dst_unused
578
579 if ((MI.getOpcode() == AMDGPU::V_FMAC_F16_sdwa ||
580 MI.getOpcode() == AMDGPU::V_FMAC_F32_sdwa ||
581 MI.getOpcode() == AMDGPU::V_MAC_F16_sdwa ||
582 MI.getOpcode() == AMDGPU::V_MAC_F32_sdwa) &&
583 getDstSel() != AMDGPU::SDWA::DWORD) {
584 // v_mac_f16/32_sdwa allow dst_sel to be equal only to DWORD
585 return false;
586 }
587
588 MachineOperand *Operand = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
589 assert(Operand &&
590 Operand->isReg() &&
591 isSameReg(*Operand, *getReplacedOperand()));
592 copyRegOperand(*Operand, *getTargetOperand());
593 MachineOperand *DstSel= TII->getNamedOperand(MI, AMDGPU::OpName::dst_sel);
594 assert(DstSel);
595
596 SdwaSel ExistingSel = static_cast<SdwaSel>(DstSel->getImm());
597 DstSel->setImm(combineSdwaSel(ExistingSel, getDstSel()).value());
598
599 MachineOperand *DstUnused= TII->getNamedOperand(MI, AMDGPU::OpName::dst_unused);
601 DstUnused->setImm(getDstUnused());
602
603 // Remove original instruction because it would conflict with our new
604 // instruction by register definition
605 getParentInst()->eraseFromParent();
606 return true;
607}
608
609bool SDWADstOperand::canCombineSelections(const MachineInstr &MI,
610 const SIInstrInfo *TII) {
611 if (!TII->isSDWA(MI.getOpcode()))
612 return true;
613
614 return canCombineOpSel(MI, TII, AMDGPU::OpName::dst_sel, getDstSel());
615}
616
617bool SDWADstPreserveOperand::convertToSDWA(MachineInstr &MI,
618 const SIInstrInfo *TII) {
619 // MI should be moved right before v_or_b32.
620 // For this we should clear all kill flags on uses of MI src-operands or else
621 // we can encounter problem with use of killed operand.
622 for (MachineOperand &MO : MI.uses()) {
623 if (!MO.isReg())
624 continue;
625 getMRI()->clearKillFlags(MO.getReg());
626 }
627
628 // Move MI before v_or_b32
629 MI.getParent()->remove(&MI);
630 getParentInst()->getParent()->insert(getParentInst(), &MI);
631
632 // Add Implicit use of preserved register
633 MachineInstrBuilder MIB(*MI.getMF(), MI);
634 MIB.addReg(getPreservedOperand()->getReg(),
635 RegState::ImplicitKill,
636 getPreservedOperand()->getSubReg());
637
638 // Tie dst to implicit use
639 MI.tieOperands(AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::vdst),
640 MI.getNumOperands() - 1);
641
642 // Convert MI as any other SDWADstOperand and remove v_or_b32
643 return SDWADstOperand::convertToSDWA(MI, TII);
644}
645
646bool SDWADstPreserveOperand::canCombineSelections(const MachineInstr &MI,
647 const SIInstrInfo *TII) {
648 return SDWADstOperand::canCombineSelections(MI, TII);
649}
650
651std::optional<int64_t>
652SIPeepholeSDWA::foldToImm(const MachineOperand &Op) const {
653 if (Op.isImm()) {
654 return Op.getImm();
655 }
656
657 // If this is not immediate then it can be copy of immediate value, e.g.:
658 // %1 = S_MOV_B32 255;
659 if (Op.isReg()) {
660 for (const MachineOperand &Def : MRI->def_operands(Op.getReg())) {
661 if (!isSameReg(Op, Def))
662 continue;
663
664 const MachineInstr *DefInst = Def.getParent();
665 if (!TII->isFoldableCopy(*DefInst))
666 return std::nullopt;
667
668 const MachineOperand &Copied = DefInst->getOperand(1);
669 if (!Copied.isImm())
670 return std::nullopt;
671
672 return Copied.getImm();
673 }
674 }
675
676 return std::nullopt;
677}
678
679std::optional<std::pair<MachineOperand *, SdwaSel>>
680SIPeepholeSDWA::matchAndMask(MachineInstr &MI) const {
681 if (MI.getOpcode() != AMDGPU::V_AND_B32_e32 &&
682 MI.getOpcode() != AMDGPU::V_AND_B32_e64)
683 return std::nullopt;
684
685 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
686 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
687 MachineOperand *ValSrc = Src1;
688 std::optional<int64_t> Imm = foldToImm(*Src0);
689 if (!Imm) {
690 Imm = foldToImm(*Src1);
691 ValSrc = Src0;
692 }
693 if (!Imm || (*Imm != 0x0000ffff && *Imm != 0x000000ff))
694 return std::nullopt;
695
696 return std::make_pair(ValSrc, *Imm == 0x0000ffff ? WORD_0 : BYTE_0);
697}
698
699bool SIPeepholeSDWA::isSDWAWithDstSel(const MachineInstr &Inst) const {
700 return TII->isSDWA(Inst) &&
701 AMDGPU::hasNamedOperand(Inst.getOpcode(), AMDGPU::OpName::dst_sel);
702}
703
704std::unique_ptr<SDWAOperand>
705SIPeepholeSDWA::matchSDWAOperand(MachineInstr &MI) {
706 unsigned Opcode = MI.getOpcode();
707 switch (Opcode) {
708 case AMDGPU::V_LSHRREV_B32_e32:
709 case AMDGPU::V_ASHRREV_I32_e32:
710 case AMDGPU::V_LSHLREV_B32_e32:
711 case AMDGPU::V_LSHRREV_B32_e64:
712 case AMDGPU::V_ASHRREV_I32_e64:
713 case AMDGPU::V_LSHLREV_B32_e64: {
714 // from: v_lshrrev_b32_e32 v1, 16/24, v0
715 // to SDWA src:v0 src_sel:WORD_1/BYTE_3
716
717 // from: v_ashrrev_i32_e32 v1, 16/24, v0
718 // to SDWA src:v0 src_sel:WORD_1/BYTE_3 sext:1
719
720 // from: v_lshlrev_b32_e32 v1, 16/24, v0
721 // to SDWA dst:v1 dst_sel:WORD_1/BYTE_3 dst_unused:UNUSED_PAD
722 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
723 auto Imm = foldToImm(*Src0);
724 if (!Imm)
725 break;
726
727 if (*Imm != 16 && *Imm != 24)
728 break;
729
730 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
731 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
732 if (!Src1->isReg() || Src1->getReg().isPhysical() ||
733 Dst->getReg().isPhysical())
734 break;
735
736 if (Opcode == AMDGPU::V_LSHLREV_B32_e32 ||
737 Opcode == AMDGPU::V_LSHLREV_B32_e64) {
738 return std::make_unique<SDWADstOperand>(
739 Dst, Src1, *Imm == 16 ? WORD_1 : BYTE_3, UNUSED_PAD);
740 }
741 return std::make_unique<SDWASrcOperand>(
742 Src1, Dst, *Imm == 16 ? WORD_1 : BYTE_3, false, false,
743 Opcode != AMDGPU::V_LSHRREV_B32_e32 &&
744 Opcode != AMDGPU::V_LSHRREV_B32_e64);
745 break;
746 }
747
748 case AMDGPU::V_LSHRREV_B16_e32:
749 case AMDGPU::V_LSHLREV_B16_e32:
750 case AMDGPU::V_LSHRREV_B16_e64:
751 case AMDGPU::V_LSHRREV_B16_opsel_e64:
752 case AMDGPU::V_LSHLREV_B16_opsel_e64:
753 case AMDGPU::V_LSHLREV_B16_e64: {
754 // V_ASHRREV_I16_e32 and V_ASHRREV_I16_e64 are
755 // not included here because they zero-fill the high 16-bits.
756
757 // from: v_lshrrev_b16_e32 v1, 8, v0
758 // to SDWA src:v0 src_sel:BYTE_1
759
760 // from: v_lshlrev_b16_e32 v1, 8, v0
761 // to SDWA dst:v1 dst_sel:BYTE_1 dst_unused:UNUSED_PAD
762 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
763 auto Imm = foldToImm(*Src0);
764 if (!Imm || *Imm != 8)
765 break;
766
767 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
768 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
769
770 if (!Src1->isReg() || Src1->getReg().isPhysical() ||
771 Dst->getReg().isPhysical())
772 break;
773
774 if (Opcode == AMDGPU::V_LSHLREV_B16_e32 ||
775 Opcode == AMDGPU::V_LSHLREV_B16_opsel_e64 ||
776 Opcode == AMDGPU::V_LSHLREV_B16_e64)
777 return std::make_unique<SDWADstOperand>(Dst, Src1, BYTE_1, UNUSED_PAD);
778 return std::make_unique<SDWASrcOperand>(Src1, Dst, BYTE_1, false, false,
779 false);
780 break;
781 }
782
783 case AMDGPU::V_BFE_I32_e64:
784 case AMDGPU::V_BFE_U32_e64: {
785 // e.g.:
786 // from: v_bfe_u32 v1, v0, 8, 8
787 // to SDWA src:v0 src_sel:BYTE_1
788
789 // offset | width | src_sel
790 // ------------------------
791 // 0 | 8 | BYTE_0
792 // 0 | 16 | WORD_0
793 // 0 | 32 | DWORD ?
794 // 8 | 8 | BYTE_1
795 // 16 | 8 | BYTE_2
796 // 16 | 16 | WORD_1
797 // 24 | 8 | BYTE_3
798
799 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
800 auto Offset = foldToImm(*Src1);
801 if (!Offset)
802 break;
803
804 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
805 auto Width = foldToImm(*Src2);
806 if (!Width)
807 break;
808
809 SdwaSel SrcSel = DWORD;
810
811 if (*Offset == 0 && *Width == 8)
812 SrcSel = BYTE_0;
813 else if (*Offset == 0 && *Width == 16)
814 SrcSel = WORD_0;
815 else if (*Offset == 0 && *Width == 32)
816 SrcSel = DWORD;
817 else if (*Offset == 8 && *Width == 8)
818 SrcSel = BYTE_1;
819 else if (*Offset == 16 && *Width == 8)
820 SrcSel = BYTE_2;
821 else if (*Offset == 16 && *Width == 16)
822 SrcSel = WORD_1;
823 else if (*Offset == 24 && *Width == 8)
824 SrcSel = BYTE_3;
825 else
826 break;
827
828 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
829 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
830
831 if (!Src0->isReg() || Src0->getReg().isPhysical() ||
832 Dst->getReg().isPhysical())
833 break;
834
835 return std::make_unique<SDWASrcOperand>(
836 Src0, Dst, SrcSel, false, false, Opcode != AMDGPU::V_BFE_U32_e64);
837 }
838
839 case AMDGPU::V_AND_B32_e32:
840 case AMDGPU::V_AND_B32_e64: {
841 // e.g.:
842 // from: v_and_b32_e32 v1, 0x0000ffff/0x000000ff, v0
843 // to SDWA src:v0 src_sel:WORD_0/BYTE_0
844 auto Mask = matchAndMask(MI);
845 if (!Mask)
846 break;
847 MachineOperand *ValSrc = Mask->first;
848
849 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
850
851 if (!ValSrc->isReg() || ValSrc->getReg().isPhysical() ||
852 Dst->getReg().isPhysical())
853 break;
854
855 return std::make_unique<SDWASrcOperand>(ValSrc, Dst, Mask->second);
856 }
857
858 case AMDGPU::V_OR_B32_e32:
859 case AMDGPU::V_OR_B32_e64: {
860 // Patterns for dst_unused:UNUSED_PRESERVE.
861 // e.g., from:
862 // v_add_f16_sdwa v0, v1, v2 dst_sel:WORD_1 dst_unused:UNUSED_PAD
863 // src1_sel:WORD_1 src2_sel:WORD1
864 // v_add_f16_e32 v3, v1, v2
865 // v_or_b32_e32 v4, v0, v3
866 // to SDWA preserve dst:v4 dst_sel:WORD_1 dst_unused:UNUSED_PRESERVE preserve:v3
867
868 // Check if one of operands of v_or_b32 is SDWA instruction
869 using CheckRetType =
870 std::optional<std::pair<MachineOperand *, MachineOperand *>>;
871 auto CheckOROperandsForSDWA =
872 [&](const MachineOperand *Op1, const MachineOperand *Op2) -> CheckRetType {
873 if (!Op1 || !Op1->isReg() || !Op2 || !Op2->isReg())
874 return CheckRetType(std::nullopt);
875
876 MachineOperand *Op1Def = findSingleRegDef(Op1, MRI);
877 if (!Op1Def)
878 return CheckRetType(std::nullopt);
879
880 MachineInstr *Op1Inst = Op1Def->getParent();
881 if (!isSDWAWithDstSel(*Op1Inst))
882 return CheckRetType(std::nullopt);
883
884 MachineOperand *Op2Def = findSingleRegDef(Op2, MRI);
885 if (!Op2Def)
886 return CheckRetType(std::nullopt);
887
888 return CheckRetType(std::pair(Op1Def, Op2Def));
889 };
890
891 MachineOperand *OrSDWA = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
892 MachineOperand *OrOther = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
893 assert(OrSDWA && OrOther);
894 auto Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
895 if (!Res) {
896 OrSDWA = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
897 OrOther = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
898 assert(OrSDWA && OrOther);
899 Res = CheckOROperandsForSDWA(OrSDWA, OrOther);
900 if (!Res)
901 break;
902 }
903
904 MachineOperand *OrSDWADef = Res->first;
905 MachineOperand *OrOtherDef = Res->second;
906 assert(OrSDWADef && OrOtherDef);
907
908 MachineInstr *SDWAInst = OrSDWADef->getParent();
909 MachineInstr *OtherInst = OrOtherDef->getParent();
910
911 // Check that OtherInstr is actually bitwise compatible with SDWAInst = their
912 // destination patterns don't overlap. Compatible instruction can be either
913 // regular instruction with compatible bitness or SDWA instruction with
914 // correct dst_sel
915 // SDWAInst | OtherInst bitness / OtherInst dst_sel
916 // -----------------------------------------------------
917 // DWORD | no / no
918 // WORD_0 | no / BYTE_2/3, WORD_1
919 // WORD_1 | 8/16-bit instructions / BYTE_0/1, WORD_0
920 // BYTE_0 | no / BYTE_1/2/3, WORD_1
921 // BYTE_1 | 8-bit / BYTE_0/2/3, WORD_1
922 // BYTE_2 | 8/16-bit / BYTE_0/1/3. WORD_0
923 // BYTE_3 | 8/16/24-bit / BYTE_0/1/2, WORD_0
924 // E.g. if SDWAInst is v_add_f16_sdwa dst_sel:WORD_1 then v_add_f16 is OK
925 // but v_add_f32 is not.
926
927 // TODO: add support for non-SDWA instructions as OtherInst.
928 // For now this only works with SDWA instructions. For regular instructions
929 // there is no way to determine if the instruction writes only 8/16/24-bit
930 // out of full register size and all registers are at min 32-bit wide.
931 if (!isSDWAWithDstSel(*OtherInst))
932 break;
933
934 SdwaSel DstSel = static_cast<SdwaSel>(
935 TII->getNamedImmOperand(*SDWAInst, AMDGPU::OpName::dst_sel));
936 SdwaSel OtherDstSel = static_cast<SdwaSel>(
937 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_sel));
938
939 bool DstSelAgree = false;
940 switch (DstSel) {
941 case WORD_0: DstSelAgree = ((OtherDstSel == BYTE_2) ||
942 (OtherDstSel == BYTE_3) ||
943 (OtherDstSel == WORD_1));
944 break;
945 case WORD_1: DstSelAgree = ((OtherDstSel == BYTE_0) ||
946 (OtherDstSel == BYTE_1) ||
947 (OtherDstSel == WORD_0));
948 break;
949 case BYTE_0: DstSelAgree = ((OtherDstSel == BYTE_1) ||
950 (OtherDstSel == BYTE_2) ||
951 (OtherDstSel == BYTE_3) ||
952 (OtherDstSel == WORD_1));
953 break;
954 case BYTE_1: DstSelAgree = ((OtherDstSel == BYTE_0) ||
955 (OtherDstSel == BYTE_2) ||
956 (OtherDstSel == BYTE_3) ||
957 (OtherDstSel == WORD_1));
958 break;
959 case BYTE_2: DstSelAgree = ((OtherDstSel == BYTE_0) ||
960 (OtherDstSel == BYTE_1) ||
961 (OtherDstSel == BYTE_3) ||
962 (OtherDstSel == WORD_0));
963 break;
964 case BYTE_3: DstSelAgree = ((OtherDstSel == BYTE_0) ||
965 (OtherDstSel == BYTE_1) ||
966 (OtherDstSel == BYTE_2) ||
967 (OtherDstSel == WORD_0));
968 break;
969 default: DstSelAgree = false;
970 }
971
972 if (!DstSelAgree)
973 break;
974
975 // Also OtherInst dst_unused should be UNUSED_PAD
976 DstUnused OtherDstUnused = static_cast<DstUnused>(
977 TII->getNamedImmOperand(*OtherInst, AMDGPU::OpName::dst_unused));
978 if (OtherDstUnused != DstUnused::UNUSED_PAD)
979 break;
980
981 // Create DstPreserveOperand
982 MachineOperand *OrDst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
983 assert(OrDst && OrDst->isReg());
984
985 return std::make_unique<SDWADstPreserveOperand>(
986 OrDst, OrSDWADef, OrOtherDef, DstSel);
987
988 }
989 }
990
991 return std::unique_ptr<SDWAOperand>(nullptr);
992}
993
994#if !defined(NDEBUG)
995static raw_ostream& operator<<(raw_ostream &OS, const SDWAOperand &Operand) {
996 Operand.print(OS);
997 return OS;
998}
999#endif
1000
1001void SIPeepholeSDWA::matchSDWAOperands(MachineBasicBlock &MBB) {
1002 for (MachineInstr &MI : MBB) {
1003 if (auto Operand = matchSDWAOperand(MI)) {
1004 LLVM_DEBUG(dbgs() << "Match: " << MI << "To: " << *Operand << '\n');
1005 SDWAOperands[&MI] = std::move(Operand);
1006 ++NumSDWAPatternsFound;
1007 }
1008 }
1009}
1010
1011// Convert the V_ADD_CO_U32_e64 into V_ADD_CO_U32_e32. This allows
1012// isConvertibleToSDWA to perform its transformation on V_ADD_CO_U32_e32 into
1013// V_ADD_CO_U32_sdwa.
1014//
1015// We are transforming from a VOP3 into a VOP2 form of the instruction.
1016// %19:vgpr_32 = V_AND_B32_e32 255,
1017// killed %16:vgpr_32, implicit $exec
1018// %47:vgpr_32, %49:sreg_64_xexec = V_ADD_CO_U32_e64
1019// %26.sub0:vreg_64, %19:vgpr_32, implicit $exec
1020// %48:vgpr_32, dead %50:sreg_64_xexec = V_ADDC_U32_e64
1021// %26.sub1:vreg_64, %54:vgpr_32, killed %49:sreg_64_xexec, implicit $exec
1022//
1023// becomes
1024// %47:vgpr_32 = V_ADD_CO_U32_sdwa
1025// 0, %26.sub0:vreg_64, 0, killed %16:vgpr_32, 0, 6, 0, 6, 0,
1026// implicit-def $vcc, implicit $exec
1027// %48:vgpr_32, dead %50:sreg_64_xexec = V_ADDC_U32_e64
1028// %26.sub1:vreg_64, %54:vgpr_32, killed $vcc, implicit $exec
1029void SIPeepholeSDWA::pseudoOpConvertToVOP2(MachineInstr &MI,
1030 const GCNSubtarget &ST) const {
1031 int Opc = MI.getOpcode();
1032 assert((Opc == AMDGPU::V_ADD_CO_U32_e64 || Opc == AMDGPU::V_SUB_CO_U32_e64) &&
1033 "Currently only handles V_ADD_CO_U32_e64 or V_SUB_CO_U32_e64");
1034
1035 // Can the candidate MI be shrunk?
1036 if (!TII->canShrink(MI, *MRI))
1037 return;
1039 // Find the related ADD instruction.
1040 const MachineOperand *Sdst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst);
1041 if (!Sdst)
1042 return;
1043 MachineOperand *NextOp = findSingleRegUse(Sdst, MRI);
1044 if (!NextOp)
1045 return;
1046 MachineInstr &MISucc = *NextOp->getParent();
1047
1048 // Make sure the carry in/out are subsequently unused.
1049 MachineOperand *CarryIn = TII->getNamedOperand(MISucc, AMDGPU::OpName::src2);
1050 if (!CarryIn)
1051 return;
1052 MachineOperand *CarryOut = TII->getNamedOperand(MISucc, AMDGPU::OpName::sdst);
1053 if (!CarryOut)
1054 return;
1055 if (!MRI->hasOneNonDBGUse(CarryIn->getReg()) ||
1056 !MRI->use_nodbg_empty(CarryOut->getReg()))
1057 return;
1058 // Make sure VCC or its subregs are dead before MI.
1059 MachineBasicBlock &MBB = *MI.getParent();
1061 MBB.computeRegisterLiveness(TRI, AMDGPU::VCC, MI, 25);
1062 if (Liveness != MachineBasicBlock::LQR_Dead)
1063 return;
1064 // Check if VCC is referenced in range of (MI,MISucc].
1065 for (auto I = std::next(MI.getIterator()), E = MISucc.getIterator();
1066 I != E; ++I) {
1067 if (I->modifiesRegister(AMDGPU::VCC, TRI))
1068 return;
1069 }
1070
1071 // Replace MI with V_{SUB|ADD}_I32_e32
1072 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(Opc))
1073 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::vdst))
1074 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::src0))
1075 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::src1))
1076 .setMIFlags(MI.getFlags());
1077
1078 MI.eraseFromParent();
1079
1080 // Since the carry output of MI is now VCC, update its use in MISucc.
1081
1082 MISucc.substituteRegister(CarryIn->getReg(), TRI->getVCC(), 0, *TRI);
1083}
1084
1085/// Try to convert an \p MI in VOP3 which takes an src2 carry-in
1086/// operand into the corresponding VOP2 form which expects the
1087/// argument in VCC. To this end, add an copy from the carry-in to
1088/// VCC. The conversion will only be applied if \p MI can be shrunk
1089/// to VOP2 and if VCC can be proven to be dead before \p MI.
1090void SIPeepholeSDWA::convertVcndmaskToVOP2(MachineInstr &MI,
1091 const GCNSubtarget &ST) const {
1092 assert(MI.getOpcode() == AMDGPU::V_CNDMASK_B32_e64);
1093
1094 LLVM_DEBUG(dbgs() << "Attempting VOP2 conversion: " << MI);
1095 if (!TII->canShrink(MI, *MRI)) {
1096 LLVM_DEBUG(dbgs() << "Cannot shrink instruction\n");
1097 return;
1098 }
1099
1100 const MachineOperand &CarryIn =
1101 *TII->getNamedOperand(MI, AMDGPU::OpName::src2);
1102 Register CarryReg = CarryIn.getReg();
1103 MachineInstr *CarryDef = MRI->getVRegDef(CarryReg);
1104 if (!CarryDef) {
1105 LLVM_DEBUG(dbgs() << "Missing carry-in operand definition\n");
1106 return;
1107 }
1108
1109 // Make sure VCC or its subregs are dead before MI.
1110 MCRegister Vcc = TRI->getVCC();
1111 MachineBasicBlock &MBB = *MI.getParent();
1114 if (Liveness != MachineBasicBlock::LQR_Dead) {
1115 LLVM_DEBUG(dbgs() << "VCC not known to be dead before instruction\n");
1116 return;
1117 }
1118
1119 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(AMDGPU::COPY), Vcc).add(CarryIn);
1120
1121 auto Converted = BuildMI(MBB, MI, MI.getDebugLoc(),
1122 TII->get(AMDGPU::getVOPe32(MI.getOpcode())))
1123 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::vdst))
1124 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::src0))
1125 .add(*TII->getNamedOperand(MI, AMDGPU::OpName::src1))
1126 .setMIFlags(MI.getFlags());
1127 TII->fixImplicitOperands(*Converted);
1128 LLVM_DEBUG(dbgs() << "Converted to VOP2: " << *Converted);
1129 (void)Converted;
1130 MI.eraseFromParent();
1131}
1132
1133namespace {
1134bool isConvertibleToSDWA(MachineInstr &MI,
1135 const GCNSubtarget &ST,
1136 const SIInstrInfo* TII) {
1137 // Check if this is already an SDWA instruction
1138 unsigned Opc = MI.getOpcode();
1139 if (TII->isSDWA(Opc))
1140 return true;
1141
1142 // Can only be handled after ealier conversion to
1143 // AMDGPU::V_CNDMASK_B32_e32 which is not always possible.
1144 if (Opc == AMDGPU::V_CNDMASK_B32_e64)
1145 return false;
1146
1147 // Check if this instruction has opcode that supports SDWA
1148 if (AMDGPU::getSDWAOp(Opc) == -1)
1150
1151 if (AMDGPU::getSDWAOp(Opc) == -1)
1152 return false;
1153
1154 if (!ST.hasSDWAOmod() && TII->hasModifiersSet(MI, AMDGPU::OpName::omod))
1155 return false;
1156
1157 if (TII->isVOPC(Opc)) {
1158 if (!ST.hasSDWASdst()) {
1159 const MachineOperand *SDst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst);
1160 if (SDst && (SDst->getReg() != AMDGPU::VCC &&
1161 SDst->getReg() != AMDGPU::VCC_LO))
1162 return false;
1163 }
1164
1165 if (!ST.hasSDWAOutModsVOPC() &&
1166 (TII->hasModifiersSet(MI, AMDGPU::OpName::clamp) ||
1167 TII->hasModifiersSet(MI, AMDGPU::OpName::omod)))
1168 return false;
1169
1170 } else if (TII->getNamedOperand(MI, AMDGPU::OpName::sdst) ||
1171 !TII->getNamedOperand(MI, AMDGPU::OpName::vdst)) {
1172 return false;
1173 }
1174
1175 if (!ST.hasSDWAMac() && (Opc == AMDGPU::V_FMAC_F16_e32 ||
1176 Opc == AMDGPU::V_FMAC_F32_e32 ||
1177 Opc == AMDGPU::V_MAC_F16_e32 ||
1178 Opc == AMDGPU::V_MAC_F32_e32))
1179 return false;
1180
1181 // Check if target supports this SDWA opcode
1182 if (TII->pseudoToMCOpcode(Opc) == -1)
1183 return false;
1184
1185 if (MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0)) {
1186 if (!Src0->isReg() && !Src0->isImm())
1187 return false;
1188 }
1189
1190 if (MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1)) {
1191 if (!Src1->isReg() && !Src1->isImm())
1192 return false;
1193 }
1194
1195 return true;
1196}
1197} // namespace
1198
1199MachineInstr *SIPeepholeSDWA::createSDWAVersion(MachineInstr &MI) {
1200 unsigned Opcode = MI.getOpcode();
1201 assert(!TII->isSDWA(Opcode));
1202
1203 int SDWAOpcode = AMDGPU::getSDWAOp(Opcode);
1204 if (SDWAOpcode == -1)
1205 SDWAOpcode = AMDGPU::getSDWAOp(AMDGPU::getVOPe32(Opcode));
1206 assert(SDWAOpcode != -1);
1207
1208 const MCInstrDesc &SDWADesc = TII->get(SDWAOpcode);
1209
1210 // Create SDWA version of instruction MI and initialize its operands
1211 MachineInstrBuilder SDWAInst =
1212 BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), SDWADesc)
1213 .setMIFlags(MI.getFlags());
1214
1215 // Copy dst, if it is present in original then should also be present in SDWA
1216 MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst);
1217 if (Dst) {
1218 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::vdst));
1219 SDWAInst.add(*Dst);
1220 } else if ((Dst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst))) {
1221 assert(Dst && AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::sdst));
1222 SDWAInst.add(*Dst);
1223 } else {
1224 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::sdst));
1225 SDWAInst.addReg(TRI->getVCC(), RegState::Define);
1226 }
1227
1228 // Copy src0, initialize src0_modifiers. All sdwa instructions has src0 and
1229 // src0_modifiers (except for v_nop_sdwa, but it can't get here)
1230 MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
1231 assert(Src0 && AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src0) &&
1232 AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src0_modifiers));
1233 if (auto *Mod = TII->getNamedOperand(MI, AMDGPU::OpName::src0_modifiers))
1234 SDWAInst.addImm(Mod->getImm());
1235 else
1236 SDWAInst.addImm(0);
1237 SDWAInst.add(*Src0);
1238
1239 // Copy src1 if present, initialize src1_modifiers.
1240 MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
1241 if (Src1) {
1242 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src1) &&
1243 AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src1_modifiers));
1244 if (auto *Mod = TII->getNamedOperand(MI, AMDGPU::OpName::src1_modifiers))
1245 SDWAInst.addImm(Mod->getImm());
1246 else
1247 SDWAInst.addImm(0);
1248 SDWAInst.add(*Src1);
1249 }
1250
1251 if (SDWAOpcode == AMDGPU::V_FMAC_F16_sdwa ||
1252 SDWAOpcode == AMDGPU::V_FMAC_F32_sdwa ||
1253 SDWAOpcode == AMDGPU::V_MAC_F16_sdwa ||
1254 SDWAOpcode == AMDGPU::V_MAC_F32_sdwa) {
1255 // v_mac_f16/32 has additional src2 operand tied to vdst
1256 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
1257 assert(Src2);
1258 SDWAInst.add(*Src2);
1259 }
1260
1261 // Copy clamp if present, initialize otherwise
1262 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::clamp));
1263 MachineOperand *Clamp = TII->getNamedOperand(MI, AMDGPU::OpName::clamp);
1264 if (Clamp) {
1265 SDWAInst.add(*Clamp);
1266 } else {
1267 SDWAInst.addImm(0);
1268 }
1269
1270 // Copy omod if present, initialize otherwise if needed
1271 if (AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::omod)) {
1272 MachineOperand *OMod = TII->getNamedOperand(MI, AMDGPU::OpName::omod);
1273 if (OMod) {
1274 SDWAInst.add(*OMod);
1275 } else {
1276 SDWAInst.addImm(0);
1277 }
1278 }
1279
1280 // Initialize SDWA specific operands
1281 if (AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::dst_sel))
1282 SDWAInst.addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1283
1284 if (AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::dst_unused))
1285 SDWAInst.addImm(AMDGPU::SDWA::DstUnused::UNUSED_PAD);
1286
1287 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src0_sel));
1288 SDWAInst.addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1289
1290 if (Src1) {
1291 assert(AMDGPU::hasNamedOperand(SDWAOpcode, AMDGPU::OpName::src1_sel));
1292 SDWAInst.addImm(AMDGPU::SDWA::SdwaSel::DWORD);
1293 }
1294
1295 // Check for a preserved register that needs to be copied.
1296 MachineInstr *Ret = SDWAInst.getInstr();
1297 TII->fixImplicitOperands(*Ret);
1298 return Ret;
1299}
1300
1301bool SIPeepholeSDWA::convertToSDWA(MachineInstr &MI,
1302 const SDWAOperandsVector &SDWAOperands) {
1303 LLVM_DEBUG(dbgs() << "Convert instruction:" << MI);
1304
1305 MachineInstr *SDWAInst;
1306 if (TII->isSDWA(MI.getOpcode())) {
1307 // Clone the instruction to allow revoking changes
1308 // made to MI during the processing of the operands
1309 // if the conversion fails.
1310 SDWAInst = MI.getMF()->CloneMachineInstr(&MI);
1311 MI.getParent()->insert(MI.getIterator(), SDWAInst);
1312 } else {
1313 SDWAInst = createSDWAVersion(MI);
1314 }
1315
1316 // Apply all sdwa operand patterns.
1317 bool Converted = false;
1318 for (auto &Operand : SDWAOperands) {
1319 LLVM_DEBUG(dbgs() << *SDWAInst << "\nOperand: " << *Operand);
1320 // There should be no intersection between SDWA operands and potential MIs
1321 // e.g.:
1322 // v_and_b32 v0, 0xff, v1 -> src:v1 sel:BYTE_0
1323 // v_and_b32 v2, 0xff, v0 -> src:v0 sel:BYTE_0
1324 // v_add_u32 v3, v4, v2
1325 //
1326 // In that example it is possible that we would fold 2nd instruction into
1327 // 3rd (v_add_u32_sdwa) and then try to fold 1st instruction into 2nd (that
1328 // was already destroyed). So if SDWAOperand is also a potential MI then do
1329 // not apply it.
1330 if (PotentialMatches.count(Operand->getParentInst()) == 0)
1331 Converted |= Operand->convertToSDWA(*SDWAInst, TII);
1332 }
1333
1334 if (!Converted) {
1335 SDWAInst->eraseFromParent();
1336 return false;
1337 }
1338
1339 ConvertedInstructions.push_back(SDWAInst);
1340 for (MachineOperand &MO : SDWAInst->uses()) {
1341 if (!MO.isReg())
1342 continue;
1343
1344 MRI->clearKillFlags(MO.getReg());
1345 }
1346 LLVM_DEBUG(dbgs() << "\nInto:" << *SDWAInst << '\n');
1347 ++NumSDWAInstructionsPeepholed;
1348
1349 MI.eraseFromParent();
1350 return true;
1351}
1352
1353// If an instruction was converted to SDWA it should not have immediates or SGPR
1354// operands (allowed one SGPR on GFX9). Copy its scalar operands into VGPRs.
1355void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &MI,
1356 const GCNSubtarget &ST) const {
1357 const MCInstrDesc &Desc = TII->get(MI.getOpcode());
1358 unsigned ConstantBusCount = 0;
1359 for (MachineOperand &Op : MI.explicit_uses()) {
1360 if (Op.isReg()) {
1361 if (TRI->isVGPR(*MRI, Op.getReg()))
1362 continue;
1363
1364 if (ST.hasSDWAScalar() && ConstantBusCount == 0) {
1365 ++ConstantBusCount;
1366 continue;
1367 }
1368 } else if (!Op.isImm())
1369 continue;
1370
1371 unsigned I = Op.getOperandNo();
1372 const TargetRegisterClass *OpRC = TII->getRegClass(Desc, I);
1373 if (!OpRC || !TRI->isVSSuperClass(OpRC))
1374 continue;
1375
1376 Register VGPR = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
1377 auto Copy = BuildMI(*MI.getParent(), MI.getIterator(), MI.getDebugLoc(),
1378 TII->get(AMDGPU::V_MOV_B32_e32), VGPR);
1379 if (Op.isImm())
1380 Copy.addImm(Op.getImm());
1381 else if (Op.isReg())
1382 Copy.addReg(Op.getReg(), getKillRegState(Op.isKill()), Op.getSubReg());
1383 Op.ChangeToRegister(VGPR, false);
1384 }
1385}
1386
1387// Re-fold the masked high-half pack (hi << 16) | (z & 0xffff) into a single
1388// v_or_b32_sdwa src1_sel:WORD_0, which ISel's fused v_lshl_or_b32 blocks.
1389bool SIPeepholeSDWA::splitLshlOrForSDWA(MachineBasicBlock &MBB) {
1390 struct Candidate {
1391 MachineInstr *LshlOr;
1392 MachineInstr *AndMI;
1393 MachineOperand *Hi;
1394 MachineOperand *ValSrc;
1395 };
1396 SmallVector<Candidate, 4> Candidates;
1397
1398 for (MachineInstr &MI : MBB) {
1399 if (MI.getOpcode() != AMDGPU::V_LSHL_OR_B32_e64)
1400 continue;
1401
1402 MachineOperand *Shift = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
1403 std::optional<int64_t> ShiftImm = foldToImm(*Shift);
1404 if (!ShiftImm || *ShiftImm != 16)
1405 continue;
1406
1407 MachineOperand *Hi = TII->getNamedOperand(MI, AMDGPU::OpName::src0);
1408 MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
1409 // Src2 must be a virtual reg so getVRegDef below is valid.
1410 if (!Hi->isReg() || !Src2->isReg() || !Src2->getReg().isVirtual())
1411 continue;
1412
1413 // The 0xffff mask must come from a single-use v_and so it can be dropped.
1414 if (!MRI->hasOneNonDBGUse(Src2->getReg()))
1415 continue;
1416 MachineInstr *AndMI = MRI->getVRegDef(Src2->getReg());
1417 if (!AndMI)
1418 continue;
1419 std::optional<std::pair<MachineOperand *, SdwaSel>> Mask =
1420 matchAndMask(*AndMI);
1421 if (!Mask || Mask->second != WORD_0)
1422 continue;
1423 MachineOperand *ValSrc = Mask->first;
1424 if (!ValSrc->isReg() || !TRI->isVGPR(*MRI, ValSrc->getReg()))
1425 continue;
1426
1427 Candidates.push_back({&MI, AndMI, Hi, ValSrc});
1428 }
1429
1430 for (const Candidate &C : Candidates) {
1431 MachineOperand *Dst = TII->getNamedOperand(*C.LshlOr, AMDGPU::OpName::vdst);
1432
1433 Register ShiftReg = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass);
1434 BuildMI(*C.LshlOr->getParent(), *C.LshlOr, C.LshlOr->getDebugLoc(),
1435 TII->get(AMDGPU::V_LSHLREV_B32_e64), ShiftReg)
1436 .addImm(16)
1437 .add(*C.Hi);
1438
1439 // vdst, src0_mods, src0, src1_mods, src1, clamp, dst_sel, dst_unused,
1440 // src0_sel, src1_sel.
1441 BuildMI(*C.LshlOr->getParent(), *C.LshlOr, C.LshlOr->getDebugLoc(),
1442 TII->get(AMDGPU::V_OR_B32_sdwa))
1443 .add(*Dst)
1444 .addImm(0)
1445 .addReg(ShiftReg)
1446 .addImm(0)
1447 .add(*C.ValSrc)
1448 .addImm(0)
1449 .addImm(DWORD)
1451 .addImm(DWORD)
1452 .addImm(WORD_0);
1453
1454 MRI->clearKillFlags(C.ValSrc->getReg());
1455 C.LshlOr->eraseFromParent();
1456 C.AndMI->eraseFromParent();
1457 }
1458
1459 return !Candidates.empty();
1460}
1461
1462bool SIPeepholeSDWALegacy::runOnMachineFunction(MachineFunction &MF) {
1463 if (skipFunction(MF.getFunction()))
1464 return false;
1465
1466 return SIPeepholeSDWA().run(MF);
1467}
1468
1469bool SIPeepholeSDWA::run(MachineFunction &MF) {
1470 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
1471
1472 if (!ST.hasSDWA())
1473 return false;
1474
1475 MRI = &MF.getRegInfo();
1476 TRI = ST.getRegisterInfo();
1477 TII = ST.getInstrInfo();
1478
1479 // Find all SDWA operands in MF.
1480 bool Ret = false;
1481 for (MachineBasicBlock &MBB : MF) {
1482 bool Changed = false;
1483 do {
1484 Ret |= splitLshlOrForSDWA(MBB);
1485
1486 // Preprocess the ADD/SUB pairs so they could be SDWA'ed.
1487 // Look for a possible ADD or SUB that resulted from a previously lowered
1488 // V_{ADD|SUB}_U64_PSEUDO. The function pseudoOpConvertToVOP2
1489 // lowers the pair of instructions into e32 form.
1490 matchSDWAOperands(MBB);
1491 for (const auto &OperandPair : SDWAOperands) {
1492 const auto &Operand = OperandPair.second;
1493 MachineInstr *PotentialMI = Operand->potentialToConvert(TII, ST);
1494 if (!PotentialMI)
1495 continue;
1496
1497 switch (PotentialMI->getOpcode()) {
1498 case AMDGPU::V_ADD_CO_U32_e64:
1499 case AMDGPU::V_SUB_CO_U32_e64:
1500 pseudoOpConvertToVOP2(*PotentialMI, ST);
1501 break;
1502 case AMDGPU::V_CNDMASK_B32_e64:
1503 convertVcndmaskToVOP2(*PotentialMI, ST);
1504 break;
1505 };
1506 }
1507 SDWAOperands.clear();
1508
1509 // Generate potential match list.
1510 matchSDWAOperands(MBB);
1511
1512 for (const auto &OperandPair : SDWAOperands) {
1513 const auto &Operand = OperandPair.second;
1514 MachineInstr *PotentialMI =
1515 Operand->potentialToConvert(TII, ST, &PotentialMatches);
1516
1517 if (PotentialMI && isConvertibleToSDWA(*PotentialMI, ST, TII))
1518 PotentialMatches[PotentialMI].push_back(Operand.get());
1519 }
1520
1521 for (auto &PotentialPair : PotentialMatches) {
1522 MachineInstr &PotentialMI = *PotentialPair.first;
1523 convertToSDWA(PotentialMI, PotentialPair.second);
1524 }
1525
1526 PotentialMatches.clear();
1527 SDWAOperands.clear();
1528
1529 Changed = !ConvertedInstructions.empty();
1530
1531 if (Changed)
1532 Ret = true;
1533 while (!ConvertedInstructions.empty())
1534 legalizeScalarOperands(*ConvertedInstructions.pop_back_val(), ST);
1535 } while (Changed);
1536 }
1537
1538 return Ret;
1539}
1540
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
unsigned uint64_t
Provides AMDGPU specific target descriptions.
MachineBasicBlock & MBB
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:678
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
This file implements a map that provides insertion order iteration.
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static MachineOperand * findSingleRegDef(const MachineOperand *Reg, const MachineRegisterInfo *MRI)
static void copyRegOperand(MachineOperand &To, const MachineOperand &From)
static MachineOperand * findSingleRegUse(const MachineOperand *Reg, const MachineRegisterInfo *MRI)
static std::optional< SdwaSel > combineSdwaSel(SdwaSel Sel, SdwaSel OperandSel)
Combine an SDWA instruction's existing SDWA selection Sel with the SDWA selection OperandSel of its o...
static bool isSameReg(const MachineOperand &LHS, const MachineOperand &RHS)
static bool canCombineOpSel(const MachineInstr &MI, const SIInstrInfo *TII, AMDGPU::OpName SrcSelOpName, SdwaSel OpSel)
Verify that the SDWA selection operand SrcSelOpName of the SDWA instruction MI can be combined with t...
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:119
Value * RHS
Value * LHS
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
bool hasOptNone() const
Do not optimize this function (-O0).
Definition Function.h:685
LLVM_ABI LivenessQueryResult computeRegisterLiveness(const TargetRegisterInfo *TRI, MCRegister Reg, const_iterator Before, unsigned Neighborhood=10) const
Return whether (physical) register Reg has been defined and not killed as of just before Before.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LivenessQueryResult
Possible outcome of a register liveness query to computeRegisterLiveness()
@ LQR_Dead
Register is known to be fully dead.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void substituteRegister(Register FromReg, Register ToReg, unsigned SubIdx, const TargetRegisterInfo &RegInfo)
Replace all occurrences of FromReg with ToReg:SubIdx, properly composing subreg indices where necessa...
mop_range uses()
Returns all operands which may be register uses.
LLVM_ABI const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
MachineOperand class - Representation of each machine instruction operand.
void setSubReg(unsigned subReg)
unsigned getSubReg() const
void setImm(int64_t immVal)
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsDead(bool Val=true)
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
void setIsKill(bool Val=true)
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
void setIsUndef(bool Val=true)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI void clearKillFlags(Register Reg) const
clearKillFlags - Iterate over all the uses of the given register and clear the kill flag from the Mac...
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLVM_ABI MachineOperand * getOneNonDBGUse(Register RegNo) const
If the register has a single non-Debug use, returns it; otherwise returns nullptr.
MachineOperand * getOneDef(Register Reg) const
Returns the defining operand if there is exactly one operand defining the specified register,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
iterator_range< def_iterator > def_operands(Register Reg) const
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
self_iterator getIterator()
Definition ilist_node.h:123
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
Changed
LLVM_READONLY bool hasNamedOperand(uint64_t Opcode, OpName NamedIdx)
LLVM_READONLY int32_t getVOPe32(uint32_t Opcode)
LLVM_READONLY int32_t getSDWAOp(uint32_t Opcode)
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
@ Offset
Definition DWP.cpp:578
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr RegState getKillRegState(bool B)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
Op::Description Desc
FunctionPass * createSIPeepholeSDWALegacyPass()
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
char & SIPeepholeSDWALegacyID
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58