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